!2616 TSAOT Support Deopt

Merge pull request !2616 from 许杰/c_deopt_dev
This commit is contained in:
openharmony_ci 2022-10-14 02:31:17 +00:00 committed by Gitee
commit ceba8e7e70
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
105 changed files with 3951 additions and 2240 deletions

View File

@ -426,6 +426,7 @@ ecma_source = [
"ecmascript/builtins/builtins_weak_map.cpp",
"ecmascript/builtins/builtins_weak_ref.cpp",
"ecmascript/builtins/builtins_weak_set.cpp",
"ecmascript/calleeReg.cpp",
"ecmascript/containers/containers_arraylist.cpp",
"ecmascript/containers/containers_deque.cpp",
"ecmascript/containers/containers_hashmap.cpp",
@ -442,6 +443,7 @@ ecma_source = [
"ecmascript/containers/containers_treeset.cpp",
"ecmascript/containers/containers_vector.cpp",
"ecmascript/dfx/stackinfo/js_stackinfo.cpp",
"ecmascript/deoptimizer.cpp",
"ecmascript/dfx/vmstat/caller_stat.cpp",
"ecmascript/dfx/vmstat/runtime_stat.cpp",
"ecmascript/dfx/vm_thread_control.cpp",

View File

@ -47,7 +47,7 @@ struct ARKDeopt {
struct ARKCallsite {
CallsiteHead head;
CallSiteInfo stackmaps;
std::vector<ARKDeopt> callsite2Deopt;
std::vector<kungfu::ARKDeopt> callsite2Deopt;
bool operator < (const ARKCallsite & x) const
{
return head.calliteOffset < x.head.calliteOffset;
@ -61,6 +61,7 @@ struct ARKCallsitePackInfo {
std::vector<ARKCallsite> callsites;
};
using ArkStackMap = CallSiteInfo;
using CalleeRegAndOffsetVec = std::vector<DwarfRegAndOffsetType>;
/*
totalSize callsiteNum callsitStart callsitEnd
-----head1--------
@ -81,8 +82,5 @@ totalSize callsiteNum callsitStart callsitEnd
- INDIRECT <loc.DwarfRegNum, loc.OffsetOrSmallConstant>
- CONSTANTNDEX <LargeInt>
*/
enum class SpecVregIndex: int {
BC_OFFSET_INDEX = -3,
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_ARK_STACKMAP_H

View File

@ -131,9 +131,9 @@ void ArkStackMapParser::ParseArkStackMap(const CallsiteHead& callsiteHead, Binar
}
void ArkStackMapParser::ParseArkDeopt(const CallsiteHead& callsiteHead,
BinaryBufferParser& binBufparser, uint8_t *ptr, std::vector<ARKDeopt> &deopts) const
BinaryBufferParser& binBufparser, uint8_t *ptr, std::vector<kungfu::ARKDeopt> &deopts) const
{
ARKDeopt deopt;
kungfu::ARKDeopt deopt;
uint32_t deoptOffset = callsiteHead.deoptOffset;
uint32_t deoptNum = callsiteHead.deoptNum;
OffsetType id;
@ -171,7 +171,6 @@ void ArkStackMapParser::ParseArkDeopt(const CallsiteHead& callsiteHead,
binBufparser.ParseBuffer(reinterpret_cast<uint8_t *>(&offsetType),
sizeof(offsetType), ptr + deoptOffset);
deoptOffset += sizeof(offsetType);
ASSERT(reg == GCStackMapRegisters::SP || reg == GCStackMapRegisters::FP);
LOG_COMPILER(VERBOSE) << " reg:" << std::dec << reg << " offset:" << static_cast<int>(offsetType);
deopt.value = std::make_pair(reg, offsetType);
break;
@ -196,7 +195,7 @@ void ArkStackMapParser::ParseArkStackMapAndDeopt(uint8_t *ptr, uint32_t length)
uint32_t arkStackMapNum = callsiteHead.arkStackMapNum;
uint32_t deoptOffset = callsiteHead.deoptOffset;
uint32_t deoptNum = callsiteHead.deoptNum;
std::vector<ARKDeopt> deopts;
std::vector<kungfu::ARKDeopt> deopts;
ArkStackMap arkStackMaps;
LOG_COMPILER(VERBOSE) << " calliteOffset:0x" << std::hex << callsiteHead.calliteOffset
<< " stackmap offset:0x" << std::hex << offset << " num:" << arkStackMapNum
@ -263,7 +262,7 @@ int ArkStackMapBuilder::FindLoc(std::vector<intptr_t> &CallsitePcs, intptr_t pc)
}
void ArkStackMapBuilder::GenARKDeopt(const DeoptInfoType& deopt, std::pair<uint32_t,
std::vector<ARKDeopt>> &sizeAndArkDeopt)
std::vector<kungfu::ARKDeopt>> &sizeAndArkDeopt)
{
ASSERT(deopt.size() % 2 == 0); // 2:<id, value>
uint32_t total = 0;
@ -334,7 +333,7 @@ void ArkStackMapBuilder::GenArkCallsitePackInfo(std::vector<Pc2CallSiteInfo> &pc
result.callsites[loc].head.calliteOffset = x.first;
result.callsites[loc].head.deoptNum = deopt.size();
result.callsites[loc].head.deoptOffset = totalSize;
std::pair<uint32_t, std::vector<ARKDeopt>> sizeAndArkDeopt;
std::pair<uint32_t, std::vector<kungfu::ARKDeopt>> sizeAndArkDeopt;
GenARKDeopt(deopt, sizeAndArkDeopt);
totalSize += sizeAndArkDeopt.first;
result.callsites[loc].callsite2Deopt = sizeAndArkDeopt.second;

View File

@ -65,7 +65,7 @@ private:
void SaveArkStackMap(const ARKCallsitePackInfo& info, BinaryBufferWriter& writer);
void SaveArkCallsitePackInfo(uint8_t *ptr, uint32_t length, const ARKCallsitePackInfo& info);
int FindLoc(std::vector<intptr_t> &CallsitePcs, intptr_t pc);
void GenARKDeopt(const DeoptInfoType& deopt, std::pair<uint32_t, std::vector<ARKDeopt>> &sizeAndArkDeopt);
void GenARKDeopt(const DeoptInfoType& deopt, std::pair<uint32_t, std::vector<kungfu::ARKDeopt>> &sizeAndArkDeopt);
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_ARK_STACKMAP_BUILD_H

View File

@ -15,6 +15,7 @@
#include "ecmascript/ark_stackmap_parser.h"
#include "ecmascript/ark_stackmap_builder.h"
#include "ecmascript/compiler/assembler/assembler.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/file_loader.h"
namespace panda::ecmascript::kungfu {
@ -40,13 +41,14 @@ int ArkStackMapParser::BinaraySearch(CallsiteHead *callsiteHead, uint32_t callsi
}
void ArkStackMapParser::GetArkDeopt(uint8_t *stackmapAddr, uint32_t length,
const CallsiteHead& callsiteHead, std::vector<ARKDeopt> &deopts) const
const CallsiteHead& callsiteHead, std::vector<kungfu::ARKDeopt> &deopts) const
{
BinaryBufferParser binBufparser(stackmapAddr, length);
ParseArkDeopt(callsiteHead, binBufparser, stackmapAddr, deopts);
}
void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, ConstInfo &info, uint8_t *stackmapAddr) const
void ArkStackMapParser::GetArkDeopt(uintptr_t callSiteAddr, uint8_t *stackmapAddr,
std::vector<kungfu::ARKDeopt> &deopts) const
{
StackMapSecHead *head = reinterpret_cast<StackMapSecHead *>(stackmapAddr);
ASSERT(head != nullptr);
@ -60,8 +62,16 @@ void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, ConstInfo &info, ui
return;
}
CallsiteHead *found = callsiteHead + mid;
std::vector<ARKDeopt> deopts;
GetArkDeopt(stackmapAddr, length, *found, deopts);
}
void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, ConstInfo &info, uint8_t *stackmapAddr) const
{
std::vector<kungfu::ARKDeopt> deopts;
GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
if (deopts.empty()) {
return;
}
ARKDeopt target;
OffsetType id = static_cast<OffsetType>(SpecVregIndex::BC_OFFSET_INDEX);

View File

@ -41,12 +41,13 @@ public:
const RootBaseAndDerivedVisitor &derivedVisitor,
uintptr_t callSiteAddr, uintptr_t callsiteFp,
uintptr_t callSiteSp, uint8_t *stackmapAddr) const;
void GetArkDeopt(uintptr_t callSiteAddr, uint8_t *stackmapAddr, std::vector<kungfu::ARKDeopt>& deopts) const;
private:
int BinaraySearch(CallsiteHead *callsiteHead, uint32_t callsiteNum, uintptr_t callSiteAddr) const;
void GetArkDeopt(uint8_t *stackmapAddr, uint32_t length, const CallsiteHead& callsiteHead,
std::vector<ARKDeopt>& deopt) const;
std::vector<kungfu::ARKDeopt>& deopt) const;
void ParseArkDeopt(const CallsiteHead& callsiteHead, BinaryBufferParser& binBufparser,
uint8_t *ptr, std::vector<ARKDeopt> &deopts) const;
uint8_t *ptr, std::vector<kungfu::ARKDeopt> &deopts) const;
void ParseArkStackMap(const CallsiteHead& callsiteHead, BinaryBufferParser& binBufparser,
uint8_t *ptr, ArkStackMap &stackMap) const;
void ParseArkStackMapAndDeopt(uint8_t *ptr, uint32_t length) const;

75
ecmascript/calleeReg.cpp Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 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/calleeReg.h"
#include "libpandabase/macros.h"
#include <iostream>
namespace panda::ecmascript::kungfu {
CalleeReg::CalleeReg()
{
#if defined(PANDA_TARGET_AMD64)
reg2Location_ = {
{DwarfReg::RBX, 0},
{DwarfReg::R15, 1},
{DwarfReg::R14, 2},
{DwarfReg::R13, 3},
{DwarfReg::R12, 4},
};
#elif defined(PANDA_TARGET_ARM64)
reg2Location_ = {
{DwarfReg::D8, 0},
{DwarfReg::D9, 1},
{DwarfReg::D10, 2},
{DwarfReg::D11, 3},
{DwarfReg::D12, 4},
{DwarfReg::D13, 5},
{DwarfReg::D14, 6},
{DwarfReg::D15, 7},
{DwarfReg::X19, 8},
{DwarfReg::X20, 9},
{DwarfReg::X21, 10},
{DwarfReg::X22, 11},
{DwarfReg::X23, 12},
{DwarfReg::X24, 13},
{DwarfReg::X25, 14},
{DwarfReg::X26, 15},
{DwarfReg::X27, 16},
{DwarfReg::X28, 17},
};
#endif
}
int CalleeReg::FindCallRegOrder(const DwarfRegType reg) const
{
auto it = reg2Location_.find(static_cast<DwarfReg>(reg));
if (it != reg2Location_.end()) {
return it->second;
} else {
UNREACHABLE();
}
}
int CalleeReg::FindCallRegOrder(const DwarfReg reg) const
{
auto order = FindCallRegOrder(static_cast<DwarfRegType>(reg));
return order;
}
int CalleeReg::GetCallRegNum() const
{
return reg2Location_.size();
}
} // namespace panda::ecmascript::kungfu

70
ecmascript/calleeReg.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 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.
*/
#ifndef ECMASCRIPT_COMPILER_CALLEE_REG_H
#define ECMASCRIPT_COMPILER_CALLEE_REG_H
#include <map>
#include "ecmascript/common.h"
#include "ecmascript/llvm_stackmap_type.h"
namespace panda::ecmascript::kungfu {
#if defined(PANDA_TARGET_AMD64)
static const int MAX_CALLEE_SAVE_REIGISTER_NUM = 32;
enum class DwarfReg: DwarfRegType {
RBX = 3,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15,
};
#elif defined(PANDA_TARGET_ARM64)
static const int MAX_CALLEE_SAVE_REIGISTER_NUM = 32;
enum class DwarfReg: DwarfRegType {
D8 = 8,
D9 = 9,
D10 = 10,
D11 = 11,
D12 = 12,
D13 = 13,
D14 = 14,
D15 = 15,
X19 = 19,
X20 = 20,
X21 = 21,
X22 = 22,
X23 = 23,
X24 = 24,
X25 = 25,
X26 = 26,
X27 = 27,
X28 = 28,
};
#else
static const int MAX_CALLEE_SAVE_REIGISTER_NUM = 16;
enum class DwarfReg: DwarfRegType {
};
#endif
class CalleeReg {
public:
PUBLIC_API CalleeReg();
virtual PUBLIC_API ~CalleeReg() = default;
int PUBLIC_API FindCallRegOrder(const DwarfRegType reg) const;
int PUBLIC_API FindCallRegOrder(const DwarfReg reg) const;
int PUBLIC_API GetCallRegNum() const;
private:
std::map<DwarfReg, int> reg2Location_;
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_COMPILER_CALLEE_REG_H

View File

@ -60,15 +60,20 @@ source_set("libark_jsoptimizer_set") {
"circuit_optimizer.cpp",
"common_stubs.cpp",
"file_generators.cpp",
"frame_states.cpp",
"gate.cpp",
"gate_accessor.cpp",
"guard_eliminating.cpp",
"guard_lowering.cpp",
"ic_stub_builder.cpp",
"interpreter_stub.cpp",
"llvm_codegen.cpp",
"llvm_ir_builder.cpp",
"new_object_stub_builder.cpp",
"pass_manager.cpp",
"rt_call_signature.cpp",
"scheduler.cpp",
"slowpath_lowering.cpp",
"stub.cpp",
"stub_builder.cpp",
"test_stubs.cpp",
@ -79,8 +84,10 @@ source_set("libark_jsoptimizer_set") {
"trampoline/x64/asm_interpreter_call.cpp",
"trampoline/x64/common_call.cpp",
"trampoline/x64/optimized_call.cpp",
"ts_type_lowering.cpp",
"type.cpp",
"type_inference/type_infer.cpp",
"type_lowering.cpp",
"type_recorder.cpp",
"verifier.cpp",
]
@ -186,13 +193,7 @@ source_set("ark_stub_compiler_set") {
}
source_set("ark_aot_compiler_set") {
sources = [
"aot_compiler.cpp",
"pass_manager.cpp",
"slowpath_lowering.cpp",
"ts_type_lowering.cpp",
"type_lowering.cpp",
]
sources = [ "aot_compiler.cpp" ]
public_configs = [
":include_llvm",

View File

@ -54,6 +54,10 @@ public:
// method must be set
GateRef GetArgGate(const size_t currentVreg) const;
GateRef GetCommonArgGate(const CommonArgIdx arg) const;
GateRef ArgsAt(const size_t index) const
{
return args_.at(index);
}
void FillArgsGateType(const TypeRecorder *typeRecorder);
void CollectArgs();
static size_t GetFixArgsNum()

View File

@ -25,7 +25,8 @@ using namespace panda::ecmascript::kungfu;
// ExtendAssembler implements frequently-used assembler macros.
class ExtendedAssembler : public AssemblerAarch64 {
public:
static const int PAIR_SLOT_SIZE = 16;
static constexpr int FRAME_SLOT_SIZE = 8;
static constexpr int PAIR_SLOT_SIZE = 16;
explicit ExtendedAssembler(Chunk *chunk, AssemblerModule *module)
: AssemblerAarch64(chunk), module_(module)
{

View File

@ -14,7 +14,7 @@
*/
#include "ecmascript/compiler/assembler/x64/extended_assembler_x64.h"
#include "ecmascript/calleeReg.h"
#include "ecmascript/frames.h"
namespace panda::ecmascript::x64 {
@ -52,6 +52,11 @@ void ExtendedAssembler::PopCppCalleeSaveRegisters()
Popq(r12);
}
void ExtendedAssembler::UpdateCalleeSaveRegisters()
{
Addq(8 * 5, rsp); // 8: 8 bytes, 5: number of CalleeSaveRegisters
}
void ExtendedAssembler::PushGhcCalleeSaveRegisters()
{
Pushq(r10);

View File

@ -24,6 +24,7 @@ namespace panda::ecmascript::x64 {
// ExtendedAssembler implements frequently-used assembler macros with some extended usages.
class ExtendedAssembler : public AssemblerX64 {
public:
static constexpr int FRAME_SLOT_SIZE = 8;
explicit ExtendedAssembler(Chunk *chunk, kungfu::AssemblerModule *module)
: AssemblerX64(chunk), module_(module)
{
@ -34,6 +35,7 @@ public:
void PopAlignBytes();
void PushCppCalleeSaveRegisters();
void PopCppCalleeSaveRegisters();
void UpdateCalleeSaveRegisters();
void PushGhcCalleeSaveRegisters();
void PopGhcCalleeSaveRegisters();
void PushArgsWithArgv(Register argc, Register argv, Register operatorRegister);

View File

@ -25,19 +25,25 @@ namespace panda::ecmascript::kungfu {
class AsyncFunctionLowering {
public:
AsyncFunctionLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, CompilationConfig *cmpCfg,
bool enableLog)
bool enableLog, const std::string& name)
: bcBuilder_(bcBuilder), circuit_(circuit), builder_(circuit, cmpCfg), enableLog_(enableLog),
stateEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY))),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))),
accessor_(circuit), argAccessor_(circuit)
stateEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY))),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))),
accessor_(circuit), argAccessor_(circuit), methodName_(name)
{
}
~AsyncFunctionLowering() = default;
void ProcessAll();
bool IsAsyncRelated() const;
const std::string& GetMethodName() const
{
return methodName_;
}
private:
void ProcessJumpTable();
@ -56,6 +62,7 @@ private:
GateRef dependEntry_ {Circuit::NullGate()};
GateAccessor accessor_;
ArgumentAccessor argAccessor_;
std::string methodName_;
};
} // panda::ecmascript::kungfu

View File

@ -26,29 +26,31 @@ CallSignature BytecodeStubCSigns::bcDebuggerHandlerCSign_;
void BytecodeStubCSigns::Initialize()
{
#define INIT_SIGNATURES(name) \
BytecodeHandlerCallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(ID_##name); \
callSigns_[name].SetName(#name); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \
new name##StubBuilder(&callSigns_[name], \
static_cast<Environment*>(env))); \
#define INIT_SIGNATURES(name) \
BytecodeHandlerCallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(ID_##name); \
callSigns_[name].SetName(std::string("BCStub_") + #name); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \
new name##StubBuilder(&callSigns_[name], \
static_cast<Environment*>(env))); \
});
INTERPRETER_BC_STUB_LIST(INIT_SIGNATURES)
#undef INIT_SIGNATURES
#define INIT_HELPER_SIGNATURES(name) \
BytecodeHandlerCallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(ID_##name); \
callSigns_[name].SetName(#name); \
callSigns_[name].SetName(std::string("BCStub_") + #name); \
callSigns_[name].SetTargetKind(CallSignature::TargetKind::BYTECODE_HELPER_HANDLER); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \
new name##StubBuilder(&callSigns_[name], static_cast<Environment*>(env))); \
});
ASM_INTERPRETER_BC_HELPER_STUB_LIST(INIT_HELPER_SIGNATURES)
#undef INIT_HELPER_SIGNATURES

View File

@ -23,16 +23,17 @@ CallSignature BuiltinsStubCSigns::builtinsCSign_;
void BuiltinsStubCSigns::Initialize()
{
#define INIT_SIGNATURES(name) \
BuiltinsCallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(name); \
callSigns_[name].SetName(#name); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \
new name##StubBuilder(&callSigns_[name], \
static_cast<Environment*>(env))); \
#define INIT_SIGNATURES(name) \
BuiltinsCallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(name); \
callSigns_[name].SetName(std::string("BuiltinStub_") + #name); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \
new name##StubBuilder(&callSigns_[name], \
static_cast<Environment*>(env))); \
});
BUILTINS_STUB_LIST(INIT_SIGNATURES)
#undef INIT_SIGNATURES
BuiltinsCallSignature::Initialize(&builtinsCSign_);

View File

@ -252,10 +252,6 @@ void BytecodeCircuitBuilder::CompleteBytecodeBlockInfo()
{
std::sort(bytecodeBlockInfos_.begin(), bytecodeBlockInfos_.end());
if (IsLogEnabled()) {
PrintCollectBlockInfo(bytecodeBlockInfos_);
}
// Deduplicate
auto deduplicateIndex = std::unique(bytecodeBlockInfos_.begin(), bytecodeBlockInfos_.end());
bytecodeBlockInfos_.erase(deduplicateIndex, bytecodeBlockInfos_.end());
@ -314,14 +310,10 @@ void BytecodeCircuitBuilder::CompleteBytecodeBlockInfo()
// Deduplicate
deduplicateIndex = std::unique(bytecodeBlockInfos_.begin(), bytecodeBlockInfos_.end());
bytecodeBlockInfos_.erase(deduplicateIndex, bytecodeBlockInfos_.end());
if (IsLogEnabled()) {
PrintCollectBlockInfo(bytecodeBlockInfos_);
}
}
void BytecodeCircuitBuilder::BuildBasicBlocks(std::map<std::pair<uint8_t *, uint8_t *>,
std::vector<uint8_t *>> &exception)
std::vector<uint8_t *>> &exception)
{
std::map<uint8_t *, BytecodeRegion *> startPcToBB; // [start, bb]
std::map<uint8_t *, BytecodeRegion *> endPcToBB; // [end, bb]
@ -385,7 +377,7 @@ void BytecodeCircuitBuilder::BuildBasicBlocks(std::map<std::pair<uint8_t *, uint
}
if (IsLogEnabled()) {
PrintGraph();
PrintGraph("Build Basic Block");
}
ComputeDominatorTree();
}
@ -393,10 +385,8 @@ void BytecodeCircuitBuilder::BuildBasicBlocks(std::map<std::pair<uint8_t *, uint
void BytecodeCircuitBuilder::ComputeDominatorTree()
{
// Construct graph backward order
std::map<size_t, size_t> bbIdToDfsTimestamp; // (basicblock id, dfs order)
std::unordered_map<size_t, size_t> dfsFatherIdx;
std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
std::vector<size_t> basicBlockList;
size_t timestamp = 0;
std::deque<size_t> pendingList;
std::vector<size_t> visited(graph_.size(), 0);
@ -406,38 +396,30 @@ void BytecodeCircuitBuilder::ComputeDominatorTree()
while (!pendingList.empty()) {
size_t curBlockId = pendingList.back();
pendingList.pop_back();
basicBlockList.push_back(curBlockId);
bbIdToDfsTimestamp[curBlockId] = timestamp++;
bbDfsList_.push_back(curBlockId);
bbIdToDfsTimestamp_[curBlockId] = timestamp++;
for (const auto &succBlock: graph_[curBlockId].succs) {
if (visited[succBlock->id] == 0) {
visited[succBlock->id] = 1;
pendingList.push_back(succBlock->id);
dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp[curBlockId];
dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp_[curBlockId];
}
}
}
for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
for (size_t idx = 0; idx < bbDfsList_.size(); idx++) {
bbDfsTimestampToIdx[bbDfsList_[idx]] = idx;
}
RemoveDeadRegions();
RemoveDeadRegions(bbIdToDfsTimestamp);
if (IsLogEnabled()) {
// print cfg order
for (auto iter : bbIdToDfsTimestamp) {
LOG_COMPILER(INFO) << "BB_" << iter.first << " dfs timestamp is : " << iter.second;
}
}
std::vector<size_t> immDom(basicBlockList.size()); // immediate dominator with dfs order index
std::vector<size_t> semiDom(basicBlockList.size());
std::vector<size_t> immDom(bbDfsList_.size()); // immediate dominator with dfs order index
std::vector<size_t> semiDom(bbDfsList_.size());
std::vector<size_t> realImmDom(graph_.size()); // immediate dominator with real index
std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
std::vector<std::vector<size_t> > semiDomTree(bbDfsList_.size());
{
std::vector<size_t> parent(basicBlockList.size());
std::vector<size_t> parent(bbDfsList_.size());
std::iota(parent.begin(), parent.end(), 0);
std::vector<size_t> minIdx(basicBlockList.size());
std::vector<size_t> minIdx(bbDfsList_.size());
std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
if (parent[idx] == idx) return idx;
size_t unionFindSetRoot = unionFind(parent[idx]);
@ -453,8 +435,8 @@ void BytecodeCircuitBuilder::ComputeDominatorTree()
};
std::iota(semiDom.begin(), semiDom.end(), 0);
semiDom[0] = semiDom.size();
for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
for (const auto &preBlock : graph_[basicBlockList[idx]].preds) {
for (size_t idx = bbDfsList_.size() - 1; idx >= 1; idx--) {
for (const auto &preBlock : graph_[bbDfsList_[idx]].preds) {
if (bbDfsTimestampToIdx[preBlock->id] < idx) {
semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
} else {
@ -471,24 +453,20 @@ void BytecodeCircuitBuilder::ComputeDominatorTree()
}
}
minIdx[idx] = idx;
merge(dfsFatherIdx[basicBlockList[idx]], idx);
merge(dfsFatherIdx[bbDfsList_[idx]], idx);
semiDomTree[semiDom[idx]].push_back(idx);
}
for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
for (size_t idx = 1; idx < bbDfsList_.size(); idx++) {
if (immDom[idx] != semiDom[idx]) {
immDom[idx] = immDom[immDom[idx]];
}
realImmDom[basicBlockList[idx]] = basicBlockList[immDom[idx]];
realImmDom[bbDfsList_[idx]] = bbDfsList_[immDom[idx]];
}
semiDom[0] = 0;
}
if (IsLogEnabled()) {
// print immediate dominator
for (size_t i = 0; i < realImmDom.size(); i++) {
LOG_COMPILER(INFO) << i << " immediate dominator: " << realImmDom[i];
}
PrintGraph();
PrintGraph("Computed Dom Trees");
}
BuildImmediateDominator(realImmDom);
@ -506,16 +484,6 @@ void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &
dominatedBlock->iDominator = immDomBlock;
}
if (IsLogEnabled()) {
for (auto block : graph_) {
if (block.isDead) {
continue;
}
LOG_COMPILER(INFO) << "current block " << block.id
<< " immediate dominator block id: " << block.iDominator->id;
}
}
for (auto &block : graph_) {
if (block.isDead) {
continue;
@ -525,19 +493,6 @@ void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &
}
}
if (IsLogEnabled()) {
for (auto &block : graph_) {
if (block.isDead) {
continue;
}
std::string log("block " + std::to_string(block.id) + " dominate block has: ");
for (size_t i = 0; i < block.immDomBlocks.size(); i++) {
log += std::to_string(block.immDomBlocks[i]->id) + ",";
}
LOG_COMPILER(INFO) << log;
}
}
ComputeDomFrontiers(immDom);
InsertPhi();
UpdateCFG();
@ -568,24 +523,14 @@ void BytecodeCircuitBuilder::ComputeDomFrontiers(const std::vector<size_t> &immD
graph_[i].domFrontiers.emplace_back(*iter);
}
}
if (IsLogEnabled()) {
for (size_t i = 0; i < domFrontiers.size(); i++) {
std::string log("basic block " + std::to_string(i) + " dominate Frontiers is: ");
for (auto iter = domFrontiers[i].cbegin(); iter != domFrontiers[i].cend(); iter++) {
log += std::to_string((*iter)->id) + ", ";
}
LOG_COMPILER(INFO) << log;
}
}
}
void BytecodeCircuitBuilder::RemoveDeadRegions(const std::map<size_t, size_t> &bbIdToDfsTimestamp)
void BytecodeCircuitBuilder::RemoveDeadRegions()
{
for (auto &block: graph_) {
std::vector<BytecodeRegion *> newPreds;
for (auto &bb : block.preds) {
if (bbIdToDfsTimestamp.count(bb->id)) {
if (bbIdToDfsTimestamp_.count(bb->id)) {
newPreds.emplace_back(bb);
}
}
@ -593,7 +538,7 @@ void BytecodeCircuitBuilder::RemoveDeadRegions(const std::map<size_t, size_t> &b
}
for (auto &block : graph_) {
block.isDead = !bbIdToDfsTimestamp.count(block.id);
block.isDead = !bbIdToDfsTimestamp_.count(block.id);
if (block.isDead) {
block.succs.clear();
}
@ -607,6 +552,7 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
auto opcode = inst.GetOpcode();
info.offset = BytecodeInstruction::Size(opcode);
info.opcode = static_cast<EcmaOpcode>(opcode);
info.pcOffset = pc - method_->GetBytecodeArray();
info.accIn = inst.HasFlag(BytecodeInstruction::Flags::ACC_READ);
info.accOut = inst.HasFlag(BytecodeInstruction::Flags::ACC_WRITE);
switch (static_cast<EcmaOpcode>(opcode)) {
@ -787,21 +733,25 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
case EcmaOpcode::ADD2_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::SUB2_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::MUL2_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::DIV2_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::MOD2_IMM8_V8: {
@ -812,31 +762,37 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
case EcmaOpcode::EQ_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::NOTEQ_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::LESS_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::LESSEQ_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::GREATER_IMM8_V8: {
uint16_t v0 = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(v0));
info.deopt = true;
break;
}
case EcmaOpcode::GREATEREQ_IMM8_V8: {
uint16_t vs = READ_INST_8_1();
info.inputs.emplace_back(VirtualRegister(vs));
info.deopt = true;
break;
}
case EcmaOpcode::SHL2_IMM8_V8: {
@ -1586,6 +1542,14 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
info.inputs.emplace_back(VirtualRegister(v0));
break;
}
case EcmaOpcode::TONUMERIC_IMM8:
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::DEC_IMM8: {
info.deopt = true;
break;
}
case EcmaOpcode::NEG_IMM8:
case EcmaOpcode::NOT_IMM8:
case EcmaOpcode::JMP_IMM8:
case EcmaOpcode::JMP_IMM16:
case EcmaOpcode::JMP_IMM32:
@ -1613,11 +1577,6 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
case EcmaOpcode::TYPEOF_IMM8:
case EcmaOpcode::TYPEOF_IMM16:
case EcmaOpcode::TONUMBER_IMM8:
case EcmaOpcode::TONUMERIC_IMM8:
case EcmaOpcode::NEG_IMM8:
case EcmaOpcode::NOT_IMM8:
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::DEC_IMM8:
case EcmaOpcode::THROW_PREF_NONE:
case EcmaOpcode::GETPROPITERATOR:
case EcmaOpcode::RESUMEGENERATOR:
@ -1666,7 +1625,7 @@ void BytecodeCircuitBuilder::InsertPhi()
EnumerateBlock(bb, [this, &defsitesInfo, &bb]
([[maybe_unused]]uint8_t * pc, BytecodeInfo &bytecodeInfo) -> bool {
if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
auto numVRegs = MethodLiteral::GetNumVregs(file_, method_) + method_->GetNumArgs();
auto numVRegs = method_->GetNumberVRegs();
for (size_t i = 0; i < numVRegs; i++) {
bytecodeInfo.vregOut.emplace_back(i);
}
@ -1681,10 +1640,6 @@ void BytecodeCircuitBuilder::InsertPhi()
// handle phi generated from multiple control flow in the same source block
InsertExceptionPhi(defsitesInfo);
if (IsLogEnabled()) {
PrintDefsitesInfo(defsitesInfo);
}
for (const auto&[variable, defsites] : defsitesInfo) {
std::queue<uint16_t> workList;
for (auto blockId: defsites) {
@ -1705,7 +1660,7 @@ void BytecodeCircuitBuilder::InsertPhi()
}
if (IsLogEnabled()) {
PrintGraph();
PrintGraph("Inserted Phis");
}
}
@ -1723,7 +1678,7 @@ void BytecodeCircuitBuilder::InsertExceptionPhi(std::map<uint16_t, std::set<size
EnumerateBlock(bb, [this, &vregs]
([[maybe_unused]]uint8_t * pc, BytecodeInfo &bytecodeInfo) -> bool {
if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
auto numVRegs = MethodLiteral::GetNumVregs(file_, method_) + method_->GetNumArgs();
auto numVRegs = method_->GetNumberVRegs();
for (size_t i = 0; i < numVRegs; i++) {
vregs.insert(i);
}
@ -1788,6 +1743,7 @@ void BytecodeCircuitBuilder::BuildCircuitArgs()
argAcc_.CollectArgs();
if (hasTypes_) {
argAcc_.FillArgsGateType(&typeRecorder_);
frameStateBuilder_.BuildArgsValues(&argAcc_);
}
}
@ -2056,7 +2012,7 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, const uint8_t *pc, Ga
size_t numValueInputs = bytecodeInfo.ComputeTotalValueCount();
GateRef gate = 0;
std::vector<GateRef> inList = CreateGateInList(bytecodeInfo);
if (!bytecodeInfo.vregOut.empty() || bytecodeInfo.accOut) {
if (bytecodeInfo.IsDef()) {
gate = circuit_.NewGate(OpCode(OpCode::JS_BYTECODE), MachineType::I64, numValueInputs,
inList, GateType::AnyType());
} else {
@ -2404,12 +2360,61 @@ GateRef BytecodeCircuitBuilder::RenameVariable(const size_t bbId, const uint8_t
}
}
void BytecodeCircuitBuilder::BuildFrameState()
{
const uint8_t *predPc = nullptr;
for (auto &dfsOrder : bbDfsList_) {
auto bb = graph_[dfsOrder];
if (bb.isDead) {
continue;
}
if (bb.preds.size() != 0) {
std::sort(bb.preds.begin(), bb.preds.end(), [this](BytecodeRegion *a, BytecodeRegion *b) {
return bbIdToDfsTimestamp_[a->id] < bbIdToDfsTimestamp_[b->id];
});
auto predBb = bb.preds.at(0);
predPc = predBb->end;
}
frameStateBuilder_.AdvenceToSuccessor(predPc, bb.end);
if (bb.valueSelectorAccGate != Circuit::NullGate()) {
frameStateBuilder_.UpdateAccumulator(bb.valueSelectorAccGate);
}
for (auto &it : bb.vregToValSelectorGate) {
auto reg = it.first;
auto gate = it.second;
frameStateBuilder_.UpdateVirtualRegister(reg, gate);
}
EnumerateBlock(bb, [this](uint8_t * pc, BytecodeInfo &bytecodeInfo) -> bool {
GateRef gate = Circuit::NullGate();
if (bytecodeInfo.IsMov()) {
if (bytecodeInfo.accIn) {
gate = frameStateBuilder_.ValuesAtAccumulator();
} else if (bytecodeInfo.inputs.size() != 0) {
auto index = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
gate = frameStateBuilder_.ValuesAt(index);
}
} else if (bytecodeInfo.IsGeneral()) {
gate = byteCodeToJSGate_.at(pc);
if (bytecodeInfo.deopt) {
GateRef glue = argAcc_.GetCommonArgGate(CommonArgIdx::GLUE);
frameStateBuilder_.BindGuard(gate, bytecodeInfo.pcOffset, glue, jsgateToBytecode_);
}
} else if (bytecodeInfo.IsSetConstant()) {
gate = byteCodeToJSGate_.at(pc);
}
if (bytecodeInfo.accOut) {
frameStateBuilder_.UpdateAccumulator(gate);
}
for (const auto &out: bytecodeInfo.vregOut) {
frameStateBuilder_.UpdateVirtualRegister(out, gate);
}
return true;
});
}
}
void BytecodeCircuitBuilder::BuildCircuit()
{
if (IsLogEnabled()) {
PrintBBInfo();
}
// create arg gates array
BuildCircuitArgs();
CollectPredsInfo();
@ -2427,11 +2432,6 @@ void BytecodeCircuitBuilder::BuildCircuit()
ASSERT(bb.forwardIndex == bb.numOfStatePreds - bb.numOfLoopBacks);
}
}
if (IsLogEnabled()) {
PrintBytecodeInfo();
}
// resolve def-site of virtual regs and set all value inputs
std::vector<GateRef> gates;
circuit_.GetAllGates(gates);
@ -2464,18 +2464,27 @@ void BytecodeCircuitBuilder::BuildCircuit()
continue;
}
if (valueIdx < bytecodeInfo.inputs.size()) {
gateAcc_.NewIn(gate, inIdx,
RenameVariable(id, pc - 1,
std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId(),
false));
auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
GateRef defVreg = RenameVariable(id, pc - 1, vregId, false);
gateAcc_.NewIn(gate, inIdx, defVreg);
} else {
gateAcc_.NewIn(gate, inIdx, RenameVariable(id, pc - 1, 0, true));
GateRef defAcc = RenameVariable(id, pc - 1, 0, true);
gateAcc_.NewIn(gate, inIdx, defAcc);
}
}
}
if (hasTypes_) {
BuildFrameState();
}
if (IsLogEnabled()) {
PrintGraph("Bytecode2Gate");
LOG_COMPILER(INFO) << "\033[34m" << "============= "
<< "After bytecode2circuit lowering ["
<< methodName_ << "]"
<< " =============" << "\033[0m";
circuit_.PrintAllGates(*this);
LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
}
}
@ -2505,156 +2514,106 @@ void BytecodeCircuitBuilder::SetExistingRestore(GateRef resumeGate, uint16_t tmp
resumeRegToRestore_[pr] = restoreGate;
}
void BytecodeCircuitBuilder::PrintCollectBlockInfo(std::vector<CfgInfo> &bytecodeBlockInfos)
void BytecodeCircuitBuilder::PrintGraph(const char* title)
{
for (auto iter = bytecodeBlockInfos.cbegin(); iter != bytecodeBlockInfos.cend(); iter++) {
std::string log("offset: " + std::to_string(reinterpret_cast<uintptr_t>(iter->pc)) + " splitKind: " +
std::to_string(static_cast<int32_t>(iter->splitKind)) + " successor are: ");
auto &vec = iter->succs;
for (size_t i = 0; i < vec.size(); i++) {
log += std::to_string(reinterpret_cast<uintptr_t>(vec[i])) + " , ";
}
LOG_COMPILER(INFO) << log;
std::map<const uint8_t *, GateRef> bcToGate;
for (const auto &[key, value]: jsgateToBytecode_) {
bcToGate[value.second] = key;
}
LOG_COMPILER(INFO) << "-----------------------------------------------------------------------";
}
void BytecodeCircuitBuilder::PrintGraph()
{
LOG_COMPILER(INFO) << "======================== " << title << " ========================";
for (size_t i = 0; i < graph_.size(); i++) {
if (graph_[i].isDead) {
LOG_COMPILER(INFO) << "BB_" << graph_[i].id << ": ;predsId= invalid BB";
LOG_COMPILER(INFO) << "curStartPc: " << reinterpret_cast<uintptr_t>(graph_[i].start) <<
" curEndPc: " << reinterpret_cast<uintptr_t>(graph_[i].end);
BytecodeRegion& bb = graph_[i];
if (bb.isDead) {
LOG_COMPILER(INFO) << "B" << bb.id << ": ;preds= invalid BB";
LOG_COMPILER(INFO) << "\tBytecodePC: [" << reinterpret_cast<void*>(bb.start) << ", "
<< reinterpret_cast<void*>(bb.end) << ")";
continue;
}
std::string log("BB_" + std::to_string(graph_[i].id) + ": ;predsId= ");
for (size_t k = 0; k < graph_[i].preds.size(); ++k) {
log += std::to_string(graph_[i].preds[k]->id) + ", ";
std::string log("B" + std::to_string(bb.id) + ": ;preds= ");
for (size_t k = 0; k < bb.preds.size(); ++k) {
log += std::to_string(bb.preds[k]->id) + ", ";
}
LOG_COMPILER(INFO) << log;
LOG_COMPILER(INFO) << "curStartPc: " << reinterpret_cast<uintptr_t>(graph_[i].start) <<
" curEndPc: " << reinterpret_cast<uintptr_t>(graph_[i].end);
LOG_COMPILER(INFO) << "\tBytecodePC: [" << reinterpret_cast<void*>(bb.start) << ", "
<< reinterpret_cast<void*>(bb.end) << ")";
for (size_t j = 0; j < graph_[i].preds.size(); j++) {
LOG_COMPILER(INFO) << "predsStartPc: " << reinterpret_cast<uintptr_t>(graph_[i].preds[j]->start) <<
" predsEndPc: " << reinterpret_cast<uintptr_t>(graph_[i].preds[j]->end);
}
for (size_t j = 0; j < graph_[i].succs.size(); j++) {
LOG_COMPILER(INFO) << "succesStartPc: " << reinterpret_cast<uintptr_t>(graph_[i].succs[j]->start) <<
" succesEndPc: " << reinterpret_cast<uintptr_t>(graph_[i].succs[j]->end);
}
std::string log1("succesId: ");
for (size_t j = 0; j < graph_[i].succs.size(); j++) {
log1 += std::to_string(graph_[i].succs[j]->id) + ", ";
std::string log1("\tSucces: ");
for (size_t j = 0; j < bb.succs.size(); j++) {
log1 += std::to_string(bb.succs[j]->id) + ", ";
}
LOG_COMPILER(INFO) << log1;
for (size_t j = 0; j < graph_[i].catchs.size(); j++) {
LOG_COMPILER(INFO) << "catchStartPc: " << reinterpret_cast<uintptr_t>(graph_[i].catchs[j]->start) <<
" catchEndPc: " << reinterpret_cast<uintptr_t>(graph_[i].catchs[j]->end);
for (size_t j = 0; j < bb.catchs.size(); j++) {
LOG_COMPILER(INFO) << "\tcatch [: " << reinterpret_cast<void*>(bb.catchs[j]->start) << ", "
<< reinterpret_cast<void*>(bb.catchs[j]->end) << ")";
}
for (size_t j = 0; j < graph_[i].immDomBlocks.size(); j++) {
LOG_COMPILER(INFO) << "dominate block id: " << graph_[i].immDomBlocks[j]->id << " startPc: " <<
reinterpret_cast<uintptr_t>(graph_[i].immDomBlocks[j]->start) << " endPc: " <<
reinterpret_cast<uintptr_t>(graph_[i].immDomBlocks[j]->end);
}
if (graph_[i].iDominator) {
LOG_COMPILER(INFO) << "current block " << graph_[i].id <<
" immediate dominator is " << graph_[i].iDominator->id;
}
std::string log2("current block " + std::to_string(graph_[i].id) + " dominance Frontiers: ");
for (const auto &frontier: graph_[i].domFrontiers) {
log2 += std::to_string(frontier->id) + " , ";
}
LOG_COMPILER(INFO) << log2;
std::string log3("current block " + std::to_string(graph_[i].id) + " phi variable: ");
for (auto variable: graph_[i].phi) {
log3 += std::to_string(variable) + " , ";
}
LOG_COMPILER(INFO) << log3;
LOG_COMPILER(INFO) << "-------------------------------------------------------";
}
}
void BytecodeCircuitBuilder::PrintBytecodeInfo()
{
for (auto &bb: graph_) {
if (bb.isDead) {
continue;
}
LOG_COMPILER(INFO) << "BB_" << bb.id << ": ";
EnumerateBlock(bb, [](uint8_t * pc, BytecodeInfo &bytecodeInfo) -> bool {
std::string log;
BytecodeInstruction inst(pc);
log += "Inst_" + GetEcmaOpcodeStr(static_cast<EcmaOpcode>(inst.GetOpcode())) + ": " + "In=[";
if (bytecodeInfo.accIn) {
log += "acc,";
}
for (const auto &in: bytecodeInfo.inputs) {
if (std::holds_alternative<VirtualRegister>(in)) {
log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
}
}
log += "] Out=[";
if (bytecodeInfo.accOut) {
log += "acc,";
}
for (const auto &out: bytecodeInfo.vregOut) {
log += std::to_string(out) + ",";
}
log += "]";
LOG_COMPILER(INFO) << log;
return true;
});
}
}
void BytecodeCircuitBuilder::PrintBBInfo()
{
for (auto &bb: graph_) {
if (bb.isDead) {
continue;
}
LOG_COMPILER(INFO) << "------------------------";
LOG_COMPILER(INFO) << "block: " << bb.id;
std::string log("preds: ");
for (auto pred: bb.preds) {
log += std::to_string(pred->id) + " , ";
}
LOG_COMPILER(INFO) << log;
std::string log1("succs: ");
for (auto succ: bb.succs) {
log1 += std::to_string(succ->id) + " , ";
}
LOG_COMPILER(INFO) << log1;
std::string log2("catchs: ");
for (auto catchBlock: bb.catchs) {
log2 += std::to_string(catchBlock->id) + " , ";
}
LOG_COMPILER(INFO) << log2;
std::string log3("trys: ");
std::string log2("\tTrys: ");
for (auto tryBlock: bb.trys) {
log3 += std::to_string(tryBlock->id) + " , ";
log2 += std::to_string(tryBlock->id) + " , ";
}
LOG_COMPILER(INFO) << log2;
std::string log3 = "\tDom: ";
for (size_t j = 0; j < bb.immDomBlocks.size(); j++) {
log3 += "B" + std::to_string(bb.immDomBlocks[j]->id) + std::string(", ");
}
LOG_COMPILER(INFO) << log3;
if (bb.iDominator) {
LOG_COMPILER(INFO) << "\tIDom B" << bb.iDominator->id;
}
std::string log4("\tDom Frontiers: ");
for (const auto &frontier: bb.domFrontiers) {
log4 += std::to_string(frontier->id) + " , ";
}
LOG_COMPILER(INFO) << log4;
std::string log5("\tPhi: ");
for (auto variable: bb.phi) {
log5 += std::to_string(variable) + " , ";
}
LOG_COMPILER(INFO) << log5;
PrintBytecodeInfo(bb, bcToGate);
LOG_COMPILER(INFO) << "";
}
}
void BytecodeCircuitBuilder::PrintDefsitesInfo(const std::map<uint16_t, std::set<size_t>> &defsitesInfo)
void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb, const std::map<const uint8_t *, GateRef>& bcToGate)
{
for (const auto&[variable, defsites] : defsitesInfo) {
std::string log("variable: " + std::to_string(variable) + " locate block have: ");
for (auto id : defsites) {
log += std::to_string(id) + " , ";
}
LOG_COMPILER(INFO) << log;
if (bb.isDead) {
return;
}
LOG_COMPILER(INFO) << "\tBytecode[] = ";
EnumerateBlock(bb, [=](uint8_t * pc, BytecodeInfo &bytecodeInfo) -> bool {
std::string log;
log += std::string("\t\t< ") + GetEcmaOpcodeStr(static_cast<EcmaOpcode>(*pc)) + ", " + "In=[";
if (bytecodeInfo.accIn) {
log += "acc,";
}
for (const auto &in: bytecodeInfo.inputs) {
if (std::holds_alternative<VirtualRegister>(in)) {
log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
}
}
log += "], Out=[";
if (bytecodeInfo.accOut) {
log += "acc,";
}
for (const auto &out: bytecodeInfo.vregOut) {
log += std::to_string(out) + ",";
}
log += "] >";
LOG_COMPILER(INFO) << log;
auto r = bcToGate.find(pc);
if (r != bcToGate.end()) {
this->gateAcc_.ShortPrint(r->second);
}
return true;
});
}
} // namespace panda::ecmascript::kungfu

View File

@ -26,6 +26,7 @@
#include "ecmascript/compiler/bytecode_info_collector.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/frame_states.h"
#include "ecmascript/compiler/type_recorder.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/jspandafile/js_pandafile.h"
@ -258,8 +259,20 @@ struct BytecodeInfo {
std::vector<VRegIDType> vregOut {}; // write register
bool accIn {false}; // read acc
bool accOut {false}; // write acc
bool deopt {false}; // may trigger deopt
EcmaOpcode opcode {0};
uint16_t offset {0};
uint32_t pcOffset {0};
bool Deopt() const
{
return deopt;
}
bool IsDef() const
{
return (!vregOut.empty()) || accOut;
}
bool IsOut(VRegIDType reg, uint32_t index) const
{
@ -451,12 +464,14 @@ public:
MethodPcInfo &methodPCInfo,
TSManager *tsManager,
const CompilationConfig* cconfig,
bool enableLog)
bool enableLog,
std::string name)
: tsManager_(tsManager), circuit_(cconfig->Is64Bit()), file_(jsPandaFile), pf_(jsPandaFile->GetPandaFile()),
method_(methodLiteral), gateAcc_(&circuit_), argAcc_(&circuit_, method_, jsPandaFile),
typeRecorder_(jsPandaFile, method_, tsManager), hasTypes_(file_->HasTSTypes()),
enableLog_(enableLog), pcToBCOffset_(methodPCInfo.pcToBCOffset),
byteCodeCurPrePc_(methodPCInfo.byteCodeCurPrePc), bytecodeBlockInfos_(methodPCInfo.bytecodeBlockInfos)
byteCodeCurPrePc_(methodPCInfo.byteCodeCurPrePc), bytecodeBlockInfos_(methodPCInfo.bytecodeBlockInfos),
frameStateBuilder_(&circuit_, methodLiteral), methodName_(name)
{
}
~BytecodeCircuitBuilder() = default;
@ -514,6 +529,11 @@ public:
return file_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
BytecodeInfo GetBytecodeInfo(const uint8_t *pc);
// for external users, circuit must be built
BytecodeInfo GetByteCodeInfo(const GateRef gate)
@ -563,7 +583,7 @@ private:
void ComputeDominatorTree();
void BuildImmediateDominator(const std::vector<size_t> &immDom);
void ComputeDomFrontiers(const std::vector<size_t> &immDom);
void RemoveDeadRegions(const std::map<size_t, size_t> &dfsTimestamp);
void RemoveDeadRegions();
void InsertPhi();
void InsertExceptionPhi(std::map<uint16_t, std::set<size_t>> &defsitesInfo);
void UpdateCFG();
@ -586,12 +606,13 @@ private:
void NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef &currentPhi);
GateRef RenameVariable(const size_t bbId, const uint8_t *end, const uint16_t reg, const bool acc);
void BuildCircuit();
void BuildFrameState();
GateRef GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const;
void SetExistingRestore(GateRef resumeGate, uint16_t tmpReg, GateRef restoreGate);
void PrintCollectBlockInfo(std::vector<CfgInfo> &bytecodeBlockInfos);
void PrintGraph();
void PrintBytecodeInfo();
void PrintBBInfo();
void PrintGraph(const char* title);
void PrintBytecodeInfo(BytecodeRegion& region, const std::map<const uint8_t *, GateRef>& bcToGate);
void PrintDefsitesInfo(const std::map<uint16_t, std::set<size_t>> &defsitesInfo);
inline bool IsEntryBlock(const size_t bbId) const
@ -617,6 +638,10 @@ private:
const std::map<uint8_t *, uint8_t *> &byteCodeCurPrePc_;
std::vector<CfgInfo> &bytecodeBlockInfos_;
std::map<std::pair<kungfu::GateRef, uint16_t>, kungfu::GateRef> resumeRegToRestore_;
FrameStateBuilder frameStateBuilder_;
std::string methodName_;
std::vector<size_t> bbDfsList_;
std::map<size_t, size_t> bbIdToDfsTimestamp_; // (basicblock id, dfs order)
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H

View File

@ -1168,4 +1168,19 @@ DEF_CALL_SIGNATURE(CreateArrayFromList)
callSign->SetParameters(params.data());
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_VARARGS);
}
DEF_CALL_SIGNATURE(DeoptHandlerAsm)
{
// 1 : 1 input parameters
CallSignature deoptHandlerAsm("DeoptHandlerAsm", 0, 1,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = deoptHandlerAsm;
std::array<VariableType, 1> params = { // 1 : 1 input parameters
VariableType::NATIVE_POINTER(), // glue
};
callSign->SetVariadicArgs(false);
callSign->SetParameters(params.data());
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
callSign->SetTargetKind(CallSignature::TargetKind::DEOPT_STUB);
}
} // namespace panda::ecmascript::kungfu

View File

@ -41,6 +41,7 @@ public:
RUNTIME_STUB,
RUNTIME_STUB_VARARGS,
RUNTIME_STUB_NO_GC,
DEOPT_STUB,
BYTECODE_HANDLER,
BYTECODE_DEBUGGER_HANDLER,
BYTECODE_HELPER_HANDLER,
@ -162,6 +163,11 @@ public:
return (GetTargetKind() == TargetKind::BYTECODE_HANDLER);
}
bool IsDeoptStub() const
{
return (GetTargetKind() == TargetKind::DEOPT_STUB);
}
void SetParameters(VariableType *paramsType)
{
if (paramCounter_ > 0 && paramsType_ == nullptr) {
@ -371,6 +377,7 @@ private:
V(CreateArrayFromList) \
V(JSObjectGetMethod) \
V(JsProxyCallInternal) \
V(DeoptHandlerAsm) \
TEST_STUB_SIGNATRUE_LIST(V)
#define DECL_CALL_SIGNATURE(name) \

View File

@ -280,6 +280,9 @@ std::vector<GateRef> Circuit::GetInVector(GateRef gate) const
GateRef Circuit::GetIn(GateRef gate, size_t idx) const
{
ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
if (IsInGateNull(gate, idx)) {
return NullGate();
}
const Gate *curGate = LoadGatePtrConst(gate);
return GetGateRef(curGate->GetInGateConst(idx));
}

View File

@ -549,6 +549,31 @@ GateRef CircuitBuilder::BothAreString(GateRef x, GateRef y)
return ret;
}
template<TypedBinOp Op>
GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto numberBinaryOp = TypedBinaryOperator(MachineType::I64, Op, xType, yType,
{currentControl, currentDepend, x, y}, gateType);
currentLabel->SetControl(numberBinaryOp);
currentLabel->SetDepend(numberBinaryOp);
return numberBinaryOp;
}
template<TypedUnOp Op>
GateRef CircuitBuilder::TypedUnaryOp(GateRef x, GateType xType, GateType gateType)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto numberUnaryOp = TypedUnaryOperator(MachineType::I64, Op, xType, {currentControl, currentDepend, x}, gateType);
currentLabel->SetControl(numberUnaryOp);
currentLabel->SetDepend(numberUnaryOp);
return numberUnaryOp;
}
// Number operator
template<TypedBinOp Op>
GateRef CircuitBuilder::NumberBinaryOp(GateRef x, GateRef y)
@ -558,7 +583,7 @@ GateRef CircuitBuilder::NumberBinaryOp(GateRef x, GateRef y)
auto currentDepend = currentLabel->GetDepend();
auto numberBinaryOp = TypedBinaryOperator(MachineType::I64, Op,
GateType::NumberType(), GateType::NumberType(),
{currentControl, currentDepend, x, y});
{currentControl, currentDepend, x, y}, GateType::AnyType());
currentLabel->SetControl(numberBinaryOp);
currentLabel->SetDepend(numberBinaryOp);
return numberBinaryOp;

View File

@ -149,37 +149,37 @@ GateRef CircuitBuilder::Arguments(size_t index)
GateRef CircuitBuilder::TypeCheck(GateType type, GateRef gate)
{
return GetCircuit()->NewGate(OpCode(OpCode::TYPE_CHECK), static_cast<uint64_t>(type.GetType()),
return GetCircuit()->NewGate(OpCode(OpCode::TYPE_CHECK), static_cast<uint64_t>(type.Value()),
{gate}, GateType::NJSValue());
}
GateRef CircuitBuilder::TypedBinaryOperator(MachineType type, TypedBinOp binOp, GateType typeLeft, GateType typeRight,
std::vector<GateRef> inList)
std::vector<GateRef> inList, GateType gateType)
{
// get BinaryOpCode from a constant gate
auto bin = Int8(static_cast<int8_t>(binOp));
inList.emplace_back(bin);
// merge two expected types of valueIns
uint64_t operandTypes = (static_cast<uint64_t>(typeLeft.GetType()) << OPRAND_TYPE_BITS) |
static_cast<uint64_t>(typeRight.GetType());
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_BINARY_OP), type, operandTypes, inList, GateType::AnyType());
uint64_t operandTypes = (static_cast<uint64_t>(typeLeft.Value()) << OPRAND_TYPE_BITS) |
static_cast<uint64_t>(typeRight.Value());
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_BINARY_OP), type, operandTypes, inList, gateType);
}
GateRef CircuitBuilder::TypeConvert(MachineType type, GateType typeFrom, GateType typeTo,
const std::vector<GateRef>& inList)
{
// merge types of valueIns before and after convertion
uint64_t operandTypes = (static_cast<uint64_t>(typeFrom.GetType()) << OPRAND_TYPE_BITS) |
static_cast<uint64_t>(typeTo.GetType());
uint64_t operandTypes = (static_cast<uint64_t>(typeFrom.Value()) << OPRAND_TYPE_BITS) |
static_cast<uint64_t>(typeTo.Value());
return GetCircuit()->NewGate(OpCode(OpCode::TYPE_CONVERT), type, operandTypes, inList, GateType::AnyType());
}
GateRef CircuitBuilder::TypedUnaryOperator(MachineType type, TypedUnaryOp unaryOp, GateType typleVal,
const std::vector<GateRef>& inList)
GateRef CircuitBuilder::TypedUnaryOperator(MachineType type, TypedUnOp unaryOp, GateType typeVal,
const std::vector<GateRef>& inList, GateType gateType)
{
auto unaryOpIdx = static_cast<uint64_t>(unaryOp);
uint64_t bitfield = (static_cast<uint64_t>(typleVal.GetType()) << OPRAND_TYPE_BITS) | unaryOpIdx;
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_UNARY_OP), type, bitfield, inList, GateType::AnyType());
uint64_t bitfield = (static_cast<uint64_t>(typeVal.Value()) << OPRAND_TYPE_BITS) | unaryOpIdx;
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_UNARY_OP), type, bitfield, inList, gateType);
}
GateRef CircuitBuilder::Int8(int8_t val)

View File

@ -204,10 +204,10 @@ public:
// low level interface
GateRef TypeCheck(GateType type, GateRef gate);
GateRef TypedBinaryOperator(MachineType type, TypedBinOp binOp, GateType typeLeft, GateType typeRight,
std::vector<GateRef> inList);
std::vector<GateRef> inList, GateType gateType);
GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
GateRef TypedUnaryOperator(MachineType type, TypedUnaryOp unaryOp, GateType typleVal,
const std::vector<GateRef>& inList);
GateRef TypedUnaryOperator(MachineType type, TypedUnOp unaryOp, GateType typeVal,
const std::vector<GateRef>& inList, GateType gateType);
GateRef Arguments(size_t index);
GateRef Merge(GateRef *in, size_t controlCount);
GateRef Selector(OpCode opcode, MachineType machineType, GateRef control, const std::vector<GateRef> &values,
@ -373,6 +373,13 @@ public:
GateRef TaggedIsString(GateRef obj);
GateRef TaggedIsStringOrSymbol(GateRef obj);
inline GateRef GetGlobalConstantString(ConstantIndex index);
// middle ir: operations with any type
template<TypedBinOp Op>
inline GateRef TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType);
template<TypedUnOp Op>
inline GateRef TypedUnaryOp(GateRef x, GateType xType, GateType gateType);
// middle ir: Number operations
template<TypedBinOp Op>
inline GateRef NumberBinaryOp(GateRef x, GateRef y);

View File

@ -1752,7 +1752,7 @@ void GlobalValueNumbering::SplitByOpCode(const std::vector<std::shared_ptr<Parti
auto op = OpCode::Op(acc_.GetOpCode(node->GetGate()));
auto bit = acc_.GetBitField(node->GetGate());
auto mt = acc_.GetMachineType(node->GetGate());
auto gt = acc_.GetGateType(node->GetGate()).GetType();
auto gt = acc_.GetGateType(node->GetGate()).Value();
auto tp = std::make_tuple(op, bit, mt, gt);
if (opToPartition.count(tp) == 0) {
auto p = std::make_shared<Partition>(Partition());

View File

@ -25,28 +25,44 @@ using ControlFlowGraph = std::vector<std::vector<GateRef>>;
class CodeGeneratorImpl {
public:
CodeGeneratorImpl() = default;
virtual ~CodeGeneratorImpl() = default;
virtual void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
const CompilationConfig *cfg) = 0;
const CompilationConfig *cfg) = 0;
virtual void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile) = 0;
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile) = 0;
};
class CodeGenerator {
public:
explicit CodeGenerator(std::unique_ptr<CodeGeneratorImpl> &impl) : impl_(std::move(impl)) {}
explicit 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)
{
impl_->GenerateCode(circuit, graph, cfg, methodLiteral, jsPandaFile);
}
private:
std::unique_ptr<CodeGeneratorImpl> impl_{nullptr};
std::string methodName_;
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_CODE_GENERATOR_H

View File

@ -395,6 +395,7 @@ void CommonStubCSigns::Initialize()
#define INIT_SIGNATURES(name) \
name##CallSignature::Initialize(&callSigns_[name]); \
callSigns_[name].SetID(name); \
callSigns_[name].SetName(std::string("COStub_") + #name); \
callSigns_[name].SetConstructor( \
[](void* env) { \
return static_cast<void*>( \

View File

@ -38,14 +38,14 @@ void Module::CollectStackMapDes(ModuleSectionDes& des) const
std::shared_ptr<uint8_t> ptr = nullptr;
uint32_t size = 0;
ArkStackMapBuilder builder;
std::tie(ptr, size) = builder.Run(std::move(stackmapPtr), textAddr);
std::tie(ptr, size) = builder.Run(std::move(stackmapPtr), textAddr);
des.EraseSec(ElfSecName::LLVM_STACKMAP);
des.SetArkStackMapPtr(ptr);
des.SetArkStackMapSize(size);
}
void StubFileGenerator::CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name,
uint32_t bridgeModuleIdx)
uint32_t bridgeModuleIdx)
{
uint32_t funSize = 0;
for (size_t i = 0; i < asmModule_.GetFunctionCount(); i++) {
@ -88,10 +88,7 @@ void AOTFileGenerator::CollectCodeInfo()
modulePackage_[i].CollectModuleSectionDes(des);
aotInfo_.AddModuleDes(des, aotfileHashs_[i]);
}
#ifndef NDEBUG
DisassembleEachFunc(addr2name);
#endif
}
void StubFileGenerator::RunAsmAssembler()

View File

@ -67,27 +67,33 @@ public:
} else {
funcSize = codeBuff + assembler_->GetSectionSize(ElfSecName::TEXT) - entrys[j];
}
stubInfo.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entrys[j] - codeBuff, moduleIndex, delta, funcSize);
kungfu::CalleeRegAndOffsetVec info = assembler_->GetCalleeReg2Offset(func, log);
stubInfo.AddStubEntry(cs->GetTargetKind(), cs->GetID(), entrys[j] - codeBuff, moduleIndex, delta, funcSize,
info);
ASSERT(!cs->GetName().empty());
addr2name[entrys[j]] = cs->GetName();
}
}
void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AOTModulePackInfo &aotInfo,
uint32_t moduleIndex, const CompilerLog &log)
uint32_t moduleIndex, const CompilerLog &log)
{
auto engine = assembler_->GetEngine();
std::vector<std::tuple<uint64_t, size_t, int>> funcInfo; // entry、idx、delta
std::vector<std::tuple<uint64_t, size_t, int>> funcInfo; // entry idx delta
std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta
llvmModule_->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func) {
uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
uint64_t length = 0;
std::string funcName(LLVMGetValueName2(func, reinterpret_cast<size_t *>(&length)));
ASSERT(length != 0);
LOG_COMPILER(INFO) << " ";
LOG_COMPILER(INFO) << "CollectCodeInfo for AOT func: " << funcName.c_str();
addr2name[funcEntry] = funcName;
int delta = assembler_->GetFpDeltaPrevFramSp(func, log);
ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
funcInfo.emplace_back(std::tuple(funcEntry, idx, delta));
kungfu::CalleeRegAndOffsetVec info = assembler_->GetCalleeReg2Offset(func, log);
calleeSaveRegisters.emplace_back(info);
});
auto codeBuff = assembler_->GetSectionAddr(ElfSecName::TEXT);
const size_t funcCount = funcInfo.size();
@ -105,7 +111,7 @@ public:
funcSize = codeBuff + assembler_->GetSectionSize(ElfSecName::TEXT) - funcEntry;
}
aotInfo.AddStubEntry(CallSignature::TargetKind::JSFUNCTION, idx,
funcEntry - codeBuff, moduleIndex, delta, funcSize);
funcEntry - codeBuff, moduleIndex, delta, funcSize, calleeSaveRegisters[i]);
}
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 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/compiler/argument_accessor.h"
#include "ecmascript/compiler/frame_states.h"
namespace panda::ecmascript::kungfu {
FrameStateInfo *FrameStateInfo::Clone()
{
return new FrameStateInfo(this);
}
FrameStateBuilder::FrameStateBuilder(Circuit *circuit, const MethodLiteral *literal)
: literal_(literal), circuit_(circuit), gateAcc_(circuit)
{
currentInfo_ = new FrameStateInfo(literal_);
}
FrameStateBuilder::~FrameStateBuilder()
{
for (auto &it : stateInfos_) {
auto state = it.second;
delete state;
}
stateInfos_.clear();
currentInfo_ = nullptr;
}
void FrameStateBuilder::BuildArgsValues(ArgumentAccessor *argAcc)
{
auto callFieldNumVregs = literal_->GetNumVregsWithCallField();
auto undefinedGate = circuit_->GetConstantGate(MachineType::I64,
JSTaggedValue::VALUE_UNDEFINED,
GateType::TaggedValue());
auto values = currentInfo_->GetValues();
for (size_t i = 0; i < callFieldNumVregs; i++) {
values->push_back(undefinedGate);
}
if (literal_->HaveFuncWithCallField()) {
auto gate = argAcc->GetCommonArgGate(CommonArgIdx::FUNC);
values->push_back(gate);
}
if (literal_->HaveNewTargetWithCallField()) {
auto gate = argAcc->GetCommonArgGate(CommonArgIdx::NEW_TARGET);
values->push_back(gate);
}
if (literal_->HaveThisWithCallField()) {
auto gate = argAcc->GetCommonArgGate(CommonArgIdx::THIS);
values->push_back(gate);
}
auto numArgs = literal_->GetNumArgsWithCallField();
for (size_t i = 0; i < numArgs; i++) {
auto gate = argAcc->ArgsAt(i + static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS));
values->push_back(gate);
}
// push acc
values->push_back(undefinedGate);
ASSERT(currentInfo_->GetNumberVRegs() == values->size());
}
GateRef FrameStateBuilder::FrameState(size_t pcOffset,
std::map<GateRef, std::pair<size_t, const uint8_t *>> &jsgateToBytecode)
{
auto numVregs = currentInfo_->GetNumberVRegs();
size_t frameStateInputs = numVregs + 1; // +1: for pc
std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
for (size_t i = 0; i < numVregs; i++) {
auto iter = jsgateToBytecode.find(ValuesAt(i));
if (iter != jsgateToBytecode.end()) {
auto pc = iter->second.second;
BytecodeInstruction inst(pc);
EcmaOpcode op = inst.GetOpcode();
// vreg needed remove from framstate if it comes from RESUMEGENERATOR, otherwisethe upperbound will not be
// found
if (op == EcmaOpcode::RESUMEGENERATOR) {
inList[i] = circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED,
GateType::TaggedValue());
} else {
inList[i] = ValuesAt(i);
}
} else {
inList[i] = ValuesAt(i);
}
}
auto pcGate = circuit_->GetConstantGate(MachineType::I64,
pcOffset,
GateType::NJSValue());
inList[numVregs] = pcGate;
return circuit_->NewGate(OpCode(OpCode::FRAME_STATE), frameStateInputs, inList, GateType::Empty());
}
void FrameStateBuilder::BindGuard(GateRef gate, size_t pcOffset, GateRef glue,
std::map<GateRef, std::pair<size_t, const uint8_t *>> &jsgateToBytecode)
{
auto depend = gateAcc_.GetDep(gate);
GateRef frameState = FrameState(pcOffset, jsgateToBytecode);
auto trueGate = circuit_->GetConstantGate(MachineType::I1,
1, // 1: true
GateType::NJSValue());
GateRef guard = circuit_->NewGate(
OpCode(OpCode::GUARD), 3, {depend, trueGate, frameState, glue}, GateType::Empty());
gateAcc_.ReplaceDependIn(gate, guard);
}
void FrameStateBuilder::AdvenceToSuccessor(const uint8_t *predPc, const uint8_t *endPc)
{
size_t pcOffset = static_cast<size_t>(endPc - literal_->GetBytecodeArray());
if (predPc != nullptr) {
size_t predPcOffset = static_cast<size_t>(predPc - literal_->GetBytecodeArray());
auto predFrameInfo = stateInfos_[predPcOffset];
ASSERT(predFrameInfo != nullptr);
currentInfo_ = predFrameInfo;
currentInfo_ = CloneFrameState(pcOffset);
} else {
// for first block
stateInfos_[pcOffset] = currentInfo_;
}
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 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.
*/
#ifndef ECMASCRIPT_COMPILER_FRAME_STATE_H
#define ECMASCRIPT_COMPILER_FRAME_STATE_H
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/gate.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/jspandafile/method_literal.h"
namespace panda::ecmascript::kungfu {
class FrameStateInfo {
public:
explicit FrameStateInfo(const MethodLiteral *literal)
: numVregs_(literal->GetNumberVRegs() + 1),
accumulator_index_(GetNumberVRegs() - 1),
literal_(literal)
{
}
explicit FrameStateInfo(const FrameStateInfo *other)
: numVregs_(other->numVregs_),
accumulator_index_(other->accumulator_index_),
literal_(other->literal_)
{
values_ = other->values_;
}
size_t GetNumberVRegs() const
{
return numVregs_;
}
std::vector<GateRef> *GetValues()
{
return &values_;
}
void SetValuesAt(size_t index, GateRef gate)
{
ASSERT(gate != Circuit::NullGate());
ASSERT(index < values_.size());
values_[index] = gate;
}
GateRef ValuesAt(size_t index) const
{
ASSERT(index < values_.size());
return values_[index];
}
GateRef ValuesAtAccumulator() const
{
return ValuesAt(accumulator_index_);
}
void UpdateAccumulator(GateRef gate)
{
return UpdateVirtualRegister(accumulator_index_, gate);
}
void UpdateVirtualRegister(size_t index, GateRef gate)
{
SetValuesAt(index, gate);
}
FrameStateInfo *Clone();
private:
size_t numVregs_ {0};
size_t accumulator_index_ {0};
const MethodLiteral *literal_ {nullptr};
// [numVRegs_] [extra args] [numArgs_] [accumulator]
std::vector<GateRef> values_{};
};
class FrameStateBuilder {
public:
FrameStateBuilder(Circuit *circuit, const MethodLiteral *literal);
~FrameStateBuilder();
GateRef ValuesAt(size_t index) const
{
return currentInfo_->ValuesAt(index);
}
GateRef ValuesAtAccumulator() const
{
return currentInfo_->ValuesAtAccumulator();
}
void BuildArgsValues(ArgumentAccessor *argAcc);
void UpdateAccumulator(GateRef gate)
{
currentInfo_->UpdateAccumulator(gate);
}
void UpdateVirtualRegister(size_t index, GateRef gate)
{
currentInfo_->UpdateVirtualRegister(index, gate);
}
void BindGuard(GateRef gate, size_t pcOffset, GateRef glue,
std::map<GateRef, std::pair<size_t, const uint8_t *>> &jsgateToBytecode);
void AdvenceToSuccessor(const uint8_t *predPc, const uint8_t *endPc);
private:
FrameStateInfo *CloneFrameState(size_t pcOffset)
{
ASSERT(stateInfos_[pcOffset] == nullptr);
auto info = currentInfo_->Clone();
stateInfos_[pcOffset] = info;
return info;
}
GateRef FrameState(size_t pcOffset, std::map<GateRef, std::pair<size_t, const uint8_t *>> &jsgateToBytecode);
FrameStateInfo *currentInfo_{nullptr};
const MethodLiteral *literal_ {nullptr};
Circuit *circuit_ {nullptr};
GateAccessor gateAcc_;
std::map<size_t, FrameStateInfo *> stateInfos_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_FRAME_STATE_H

View File

@ -20,7 +20,7 @@ constexpr size_t ONE_DEPEND = 1;
constexpr size_t MANY_DEPEND = 2;
constexpr size_t NO_DEPEND = 0;
// NOLINTNEXTLINE(readability-function-size)
Properties OpCode::GetProperties() const
const Properties& OpCode::GetProperties() const
{
// general schema: [STATE]s + [DEPEND]s + [VALUE]s + [ROOT]
// GENERAL_STATE for any opcode match in
@ -44,8 +44,10 @@ Properties OpCode::GetProperties() const
switch (op_) {
// SHARED
case NOP:
case CIRCUIT_ROOT:
return {NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, NO_ROOT};
case CIRCUIT_ROOT: {
static const Properties ps { NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case STATE_ENTRY:
case DEPEND_ENTRY:
case FRAMESTATE_ENTRY:
@ -53,92 +55,172 @@ Properties OpCode::GetProperties() const
case THROW_LIST:
case CONSTANT_LIST:
case ALLOCA_LIST:
case ARG_LIST:
return {NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CIRCUIT_ROOT)};
case RETURN:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), OpCode(RETURN_LIST)};
case RETURN_VOID:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, OpCode(RETURN_LIST)};
case THROW:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(JSMachineType()), OpCode(THROW_LIST)};
case ORDINARY_BLOCK:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
case IF_BRANCH:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(I1), NO_ROOT};
case SWITCH_BRANCH:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case ARG_LIST: {
static const Properties ps { NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CIRCUIT_ROOT) };
return ps;
}
case RETURN: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
VALUE(ANYVALUE), OpCode(RETURN_LIST) };
return ps;
}
case RETURN_VOID: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE,
OpCode(RETURN_LIST) };
return ps;
}
case THROW: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(JSMachineType()),
OpCode(THROW_LIST) };
return ps;
}
case ORDINARY_BLOCK: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case IF_BRANCH: {
static const Properties ps{ NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(I1), NO_ROOT };
return ps;
}
case SWITCH_BRANCH: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case IF_TRUE:
case IF_FALSE:
return {NOVALUE, STATE(OpCode(IF_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT};
case IF_FALSE: {
static const Properties ps { NOVALUE, STATE(OpCode(IF_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case SWITCH_CASE:
case DEFAULT_CASE:
return {NOVALUE, STATE(OpCode(SWITCH_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT};
case MERGE:
return {NOVALUE, MANY_STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
case LOOP_BEGIN:
return {NOVALUE, STATE(OpCode(GENERAL_STATE), OpCode(LOOP_BACK)), NO_DEPEND, NO_VALUE, NO_ROOT};
case LOOP_BACK:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
case VALUE_SELECTOR:
return {FLEX, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(FLEX), NO_ROOT};
case DEPEND_SELECTOR:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), MANY_DEPEND, NO_VALUE, NO_ROOT};
case DEPEND_RELAY:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, NO_ROOT};
case DEPEND_AND:
return {NOVALUE, NO_STATE, MANY_DEPEND, NO_VALUE, NO_ROOT};
case DEFAULT_CASE: {
static const Properties ps { NOVALUE, STATE(OpCode(SWITCH_BRANCH)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case MERGE: {
static const Properties ps { NOVALUE, MANY_STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case LOOP_BEGIN: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE), OpCode(LOOP_BACK)), NO_DEPEND,
NO_VALUE, NO_ROOT };
return ps;
}
case LOOP_BACK: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case VALUE_SELECTOR: {
static const Properties ps { FLEX, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(FLEX), NO_ROOT };
return ps;
}
case DEPEND_SELECTOR: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), MANY_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case DEPEND_RELAY: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case DEPEND_AND: {
static const Properties ps { NOVALUE, NO_STATE, MANY_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
// High Level IR
case JS_BYTECODE:
return {FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, MANY_VALUE(ANYVALUE), NO_ROOT};
case JS_BYTECODE: {
static const Properties ps { FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
MANY_VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case IF_SUCCESS:
case IF_EXCEPTION:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT};
case GET_EXCEPTION:
return {I64, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT};
case IF_EXCEPTION: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case GET_EXCEPTION: {
static const Properties ps { I64, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
// Middle Level IR
case RUNTIME_CALL:
case NOGC_RUNTIME_CALL:
case BYTECODE_CALL:
case DEBUGGER_BYTECODE_CALL:
case BUILTINS_CALL:
case CALL:
case RUNTIME_CALL_WITH_ARGV:
return {FLEX, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
case ALLOCA:
return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ALLOCA_LIST)};
case ARG:
return {FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ARG_LIST)};
case RUNTIME_CALL_WITH_ARGV: {
static const Properties ps { FLEX, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT };
return ps;
}
case ALLOCA: {
static const Properties ps { ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ALLOCA_LIST) };
return ps;
}
case ARG: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ARG_LIST) };
return ps;
}
case MUTABLE_DATA:
case CONST_DATA:
return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
case RELOCATABLE_DATA:
return {ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
case CONSTANT:
return {FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
case ZEXT_TO_INT64:
return {I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case ZEXT_TO_INT32:
return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case ZEXT_TO_INT16:
return {I16, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case ZEXT_TO_ARCH:
return {ARCH, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case SEXT_TO_INT64:
return {I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case SEXT_TO_INT32:
return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case SEXT_TO_ARCH:
return {ARCH, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TRUNC_TO_INT32:
return {I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TRUNC_TO_INT8:
return {I8, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TRUNC_TO_INT1:
return {I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TRUNC_TO_INT16:
return {I16, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case REV:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX), NO_ROOT};
case CONST_DATA: {
static const Properties ps { ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST) };
return ps;
}
case RELOCATABLE_DATA: {
static const Properties ps { ARCH, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST) };
return ps;
}
case CONSTANT: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST) };
return ps;
}
case ZEXT_TO_INT64: {
static const Properties ps { I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case ZEXT_TO_INT32: {
static const Properties ps { I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case ZEXT_TO_INT16: {
static const Properties ps { I16, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case ZEXT_TO_ARCH: {
static const Properties ps { ARCH, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case SEXT_TO_INT64: {
static const Properties ps { I64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case SEXT_TO_INT32: {
static const Properties ps { I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case SEXT_TO_ARCH: {
static const Properties ps { ARCH, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TRUNC_TO_INT32: {
static const Properties ps { I32, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TRUNC_TO_INT8: {
static const Properties ps { I8, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TRUNC_TO_INT1: {
static const Properties ps { I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TRUNC_TO_INT16: {
static const Properties ps { I16, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case REV: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX), NO_ROOT };
return ps;
}
case ADD:
case SUB:
case MUL:
@ -154,8 +236,10 @@ Properties OpCode::GetProperties() const
case OR:
case LSL:
case LSR:
case ASR:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX, FLEX), NO_ROOT};
case ASR: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, VALUE(FLEX, FLEX), NO_ROOT };
return ps;
}
case SLT:
case SLE:
case SGT:
@ -169,50 +253,104 @@ Properties OpCode::GetProperties() const
case FGT:
case FGE:
case EQ:
case NE:
return {I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
case LOAD:
return {FLEX, NO_STATE, ONE_DEPEND, VALUE(ARCH), NO_ROOT};
case STORE:
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE, ARCH), NO_ROOT};
case TAGGED_TO_INT64:
return {I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT};
case INT64_TO_TAGGED:
return {I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT};
case NE: {
static const Properties ps { I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE, ANYVALUE), NO_ROOT };
return ps;
}
case LOAD: {
static const Properties ps { FLEX, NO_STATE, ONE_DEPEND, VALUE(ARCH), NO_ROOT };
return ps;
}
case STORE: {
static const Properties ps { NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE, ARCH), NO_ROOT };
return ps;
}
case TAGGED_TO_INT64: {
static const Properties ps { I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT };
return ps;
}
case INT64_TO_TAGGED: {
static const Properties ps { I64, NO_STATE, NO_DEPEND, VALUE(I64), NO_ROOT };
return ps;
}
case SIGNED_INT_TO_FLOAT:
case UNSIGNED_INT_TO_FLOAT:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case UNSIGNED_INT_TO_FLOAT: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case FLOAT_TO_SIGNED_INT:
case UNSIGNED_FLOAT_TO_INT:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case BITCAST:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case UNSIGNED_FLOAT_TO_INT: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case BITCAST: {
static const Properties ps { FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
// Deopt relate IR
case GUARD: {
static const Properties ps { NOVALUE, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case FRAME_STATE: {
static const Properties ps { NOVALUE, NO_STATE, NO_DEPEND, MANY_VALUE(ANYVALUE), NO_ROOT };
return ps;
}
// suspend relate HIR
case RESTORE_REGISTER:
return {FLEX, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT};
case SAVE_REGISTER:
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case RESTORE_REGISTER: {
static const Properties ps { FLEX, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT };
return ps;
}
case SAVE_REGISTER: {
static const Properties ps { NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
// ts type lowering relate IR
case TYPE_CHECK:
return {I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TYPED_BINARY_OP:
return {FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, ANYVALUE, I8), NO_ROOT};
case TYPE_CONVERT:
return {FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TYPED_UNARY_OP:
return {FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case HEAP_ALLOC:
return {ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(I64), NO_ROOT};
case LOAD_ELEMENT:
return {ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, I64), NO_ROOT};
case LOAD_PROPERTY:
return {ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
case STORE_ELEMENT:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, I64, ANYVALUE), NO_ROOT};
case STORE_PROPERTY:
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, ANYVALUE, ANYVALUE), NO_ROOT};
case TO_LENGTH:
return {I64, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case TYPE_CHECK: {
static const Properties ps { I1, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TYPED_BINARY_OP: {
static const Properties ps { FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
VALUE(ANYVALUE, ANYVALUE, I8), NO_ROOT };
return ps;
}
case TYPE_CONVERT: {
static const Properties ps { FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case TYPED_UNARY_OP: {
static const Properties ps { FLEX, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
case HEAP_ALLOC: {
static const Properties ps { ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(I64), NO_ROOT };
return ps;
}
case LOAD_ELEMENT: {
static const Properties ps { ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
VALUE(ANYVALUE, I64), NO_ROOT };
return ps;
}
case LOAD_PROPERTY: {
static const Properties ps { ANYVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE, ANYVALUE),
NO_ROOT };
return ps;
}
case STORE_ELEMENT: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
VALUE(ANYVALUE, I64, ANYVALUE), NO_ROOT };
return ps;
}
case STORE_PROPERTY: {
static const Properties ps { NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND,
VALUE(ANYVALUE, ANYVALUE, ANYVALUE), NO_ROOT };
return ps;
}
case TO_LENGTH: {
static const Properties ps { I64, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT };
return ps;
}
default:
LOG_COMPILER(ERROR) << "Please complete OpCode properties (OpCode=" << op_ << ")";
UNREACHABLE();
@ -324,6 +462,8 @@ std::string OpCode::Str() const
{FLOAT_TO_SIGNED_INT, "FLOAT_TO_SIGNED_INT"},
{UNSIGNED_FLOAT_TO_INT, "UNSIGNED_FLOAT_TO_INT"},
{BITCAST, "BITCAST"},
{GUARD, "GUARD"},
{FRAME_STATE, "FRAME_STATE"},
{RESTORE_REGISTER, "RESTORE_REGISTER"},
{SAVE_REGISTER, "SAVE_REGISTER"},
{TYPE_CHECK, "TYPE_CHECK"},
@ -833,7 +973,7 @@ bool In::IsGateNull() const
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
Gate::Gate(GateId id, OpCode opcode, MachineType bitValue, BitField bitfield, Gate *inList[], GateType type,
MarkCode mark)
: id_(id), opcode_(opcode), bitValue_(bitValue), type_(type), stamp_(1), mark_(mark), bitfield_(bitfield),
: id_(id), type_(type), opcode_(opcode), bitValue_(bitValue), stamp_(1), mark_(mark), bitfield_(bitfield),
firstOut_(0)
{
auto numIns = GetNumIns();
@ -851,7 +991,7 @@ Gate::Gate(GateId id, OpCode opcode, MachineType bitValue, BitField bitfield, Ga
}
Gate::Gate(GateId id, OpCode opcode, BitField bitfield, Gate *inList[], GateType type, MarkCode mark)
: id_(id), opcode_(opcode), type_(type), stamp_(1), mark_(mark), bitfield_(bitfield), firstOut_(0)
: id_(id), type_(type), opcode_(opcode), stamp_(1), mark_(mark), bitfield_(bitfield), firstOut_(0)
{
auto numIns = GetNumIns();
for (size_t idx = 0; idx < numIns; idx++) {
@ -1106,7 +1246,7 @@ std::string Gate::MachineTypeStr(MachineType machineType) const
std::string Gate::GateTypeStr(GateType gateType) const
{
const std::map<GateType, const char *> strMap = {
static const std::map<GateType, const char *> strMap = {
{GateType::NJSValue(), "NJS_VALUE"},
{GateType::TaggedValue(), "TAGGED_VALUE"},
{GateType::TaggedPointer(), "TAGGED_POINTER"},
@ -1115,10 +1255,15 @@ std::string Gate::GateTypeStr(GateType gateType) const
{GateType::AnyType(), "ANY_TYPE"},
};
std::string name = "";
if (strMap.count(gateType) > 0) {
return strMap.at(gateType);
name = strMap.at(gateType);
}
return "GateType-" + std::to_string(gateType.GetType());
GlobalTSTypeRef r = gateType.GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return name + std::string("-GT(M=") + std::to_string(m) +
std::string(", L=") + std::to_string(l) + std::string(")");
}
void Gate::Print(std::string bytecode, bool inListPreview, size_t highlightIdx) const
@ -1127,8 +1272,10 @@ void Gate::Print(std::string bytecode, bool inListPreview, size_t highlightIdx)
std::string log("(id=" + std::to_string(id_) + ", op=" + GetOpCode().Str() + ", ");
log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
log += ((bytecode.compare("") == 0) ? "" : ", ");
log += "machineType=" + MachineTypeStr(GetMachineType()) + ", ";
log += "bitfield=" + std::to_string(bitfield_) + ", ";
log += "MType=" + MachineTypeStr(GetMachineType()) + ", ";
std::stringstream buf;
buf << std::hex << bitfield_;
log += "bitfield=" + buf.str() + ", ";
log += "type=" + GateTypeStr(type_) + ", ";
log += "stamp=" + std::to_string(static_cast<uint32_t>(stamp_)) + ", ";
log += "mark=" + std::to_string(static_cast<uint32_t>(mark_)) + ", ";
@ -1161,7 +1308,50 @@ void Gate::Print(std::string bytecode, bool inListPreview, size_t highlightIdx)
}
}
log += "])";
log += "\n";
LOG_COMPILER(INFO) << std::dec << log;
}
}
void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlightIdx) const
{
if (GetOpCode() != OpCode::NOP) {
std::string log("(id=" + std::to_string(id_) + ", op=" + GetOpCode().Str() + ", ");
log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
log += ((bytecode.compare("") == 0) ? "" : ", ");
log += "MType=" + MachineTypeStr(GetMachineType()) + ", ";
std::stringstream buf;
buf << std::hex << bitfield_;
log += "bitfield=" + buf.str() + ", ";
log += "type=" + GateTypeStr(type_) + ", ";
log += "in=[";
size_t idx = 0;
auto stateSize = GetStateCount();
auto dependSize = GetDependCount();
auto valueSize = GetInValueCount();
auto rootSize = GetRootCount();
idx = PrintInGate(stateSize, idx, 0, inListPreview, highlightIdx, log);
idx = PrintInGate(stateSize + dependSize, idx, stateSize, inListPreview, highlightIdx, log);
idx = PrintInGate(stateSize + dependSize + valueSize, idx, stateSize + dependSize,
inListPreview, highlightIdx, log);
PrintInGate(stateSize + dependSize + valueSize + rootSize, idx, stateSize + dependSize + valueSize,
inListPreview, highlightIdx, log, true);
log += "], out=[";
if (!IsFirstOutNull()) {
const Out *curOut = GetFirstOutConst();
log += std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + curOut->GetGateConst()->GetOpCode().Str()) : std::string(""));
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
log += " " + std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + curOut->GetGateConst()->GetOpCode().Str())
: std::string(""));
}
}
log += "])";
LOG_COMPILER(INFO) << std::dec << log;
}
}
@ -1174,10 +1364,10 @@ size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPrev
log += ((idx == size) ? "" : " ");
log += ((idx == highlightIdx) ? "\033[4;31m" : "");
log += ((IsInGateNull(idx)
? "N"
: (std::to_string(GetInGateConst(idx)->GetId()) +
(inListPreview ? std::string(":" + GetInGateConst(idx)->GetOpCode().Str())
: std::string("")))));
? "N"
: (std::to_string(GetInGateConst(idx)->GetId()) +
(inListPreview ? std::string(":" + GetInGateConst(idx)->GetOpCode().Str())
: std::string("")))));
log += ((idx == highlightIdx) ? "\033[0m" : "");
}
log += "]";
@ -1238,11 +1428,6 @@ bool OpCode::IsGeneralState() const
(op_ == OpCode::STORE_ELEMENT) || (op_ == OpCode::STORE_PROPERTY));
}
bool OpCode::IsTypedGate() const
{
return ((op_ == OpCode::TYPE_CHECK) || (op_ == OpCode::TYPED_BINARY_OP) || (op_ == OpCode::TYPE_CONVERT));
}
bool OpCode::IsTerminalState() const
{
return ((op_ == OpCode::RETURN) || (op_ == OpCode::THROW) || (op_ == OpCode::RETURN_VOID));
@ -1269,4 +1454,14 @@ bool OpCode::IsNop() const
{
return (op_ == OpCode::NOP);
}
bool OpCode::IsConstant() const
{
return (op_ == OpCode::CONSTANT);
}
bool OpCode::IsTypedOperator() const
{
return (op_ == OpCode::TYPED_BINARY_OP) || (op_ == OpCode::TYPE_CONVERT) || (op_ == OpCode::TYPED_UNARY_OP);
}
} // namespace panda::ecmascript::kungfu

View File

@ -44,7 +44,7 @@ class Gate;
struct Properties;
class BytecodeCircuitBuilder;
enum MachineType { // Bit width
enum MachineType : uint8_t { // Bit width
NOVALUE,
ANYVALUE,
ARCH,
@ -81,7 +81,7 @@ enum class TypedBinOp : BinaryOp {
TYPED_EXP,
};
enum class TypedUnaryOp : uint8_t {
enum class TypedUnOp : uint8_t {
TYPED_TONUMBER,
TYPED_NEG,
TYPED_NOT,
@ -93,7 +93,7 @@ class OpCode {
public:
enum Op : GateOp {
// SHARED
NOP,
NOP = 0,
CIRCUIT_ROOT,
STATE_ENTRY,
DEPEND_ENTRY,
@ -120,6 +120,8 @@ public:
DEPEND_SELECTOR,
DEPEND_RELAY,
DEPEND_AND,
GUARD,
FRAME_STATE,
// High Level IR
JS_BYTECODE,
IF_SUCCESS,
@ -196,8 +198,6 @@ public:
TYPED_BINARY_OP,
TYPE_CONVERT,
TYPED_UNARY_OP,
// middle hir level
TO_LENGTH,
HEAP_ALLOC,
LOAD_ELEMENT,
@ -206,11 +206,11 @@ public:
STORE_PROPERTY,
COMMON_CIR_FIRST = NOP,
COMMON_CIR_LAST = DEPEND_AND,
COMMON_CIR_LAST = FRAME_STATE,
HIGH_CIR_FIRST = JS_BYTECODE,
HIGH_CIR_LAST = GET_EXCEPTION,
MID_CIR_FIRST = RUNTIME_CALL,
MID_CIR_LAST = SAVE_REGISTER
MID_CIR_LAST = STORE_PROPERTY
};
OpCode() = default;
@ -220,7 +220,6 @@ public:
return op_;
}
explicit operator bool() const = delete;
[[nodiscard]] Properties GetProperties() const;
[[nodiscard]] size_t GetStateCount(BitField bitfield) const;
[[nodiscard]] size_t GetDependCount(BitField bitfield) const;
[[nodiscard]] size_t GetInValueCount(BitField bitfield) const;
@ -236,15 +235,18 @@ public:
[[nodiscard]] bool IsSchedulable() const;
[[nodiscard]] bool IsState() const; // note: IsState(STATE_ENTRY) == false
[[nodiscard]] bool IsGeneralState() const;
[[nodiscard]] bool IsTypedGate() const;
[[nodiscard]] bool IsTerminalState() const;
[[nodiscard]] bool IsCFGMerge() const;
[[nodiscard]] bool IsControlCase() const;
[[nodiscard]] bool IsLoopHead() const;
[[nodiscard]] bool IsNop() const;
[[nodiscard]] bool IsConstant() const;
[[nodiscard]] bool IsTypedOperator() const;
~OpCode() = default;
private:
friend class Gate;
[[nodiscard]] const Properties& GetProperties() const;
Op op_;
};
@ -396,6 +398,7 @@ public:
void SetBitField(BitField bitfield);
void AppendIn(const Gate *in); // considered very slow
void Print(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
void ShortPrint(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
size_t PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
std::string &log, bool isEnd = false) const;
void PrintByteCode(std::string bytecode) const;
@ -423,14 +426,14 @@ private:
// out(2)
// out(1)
// out(0)
GateId id_ {0};
OpCode opcode_;
MachineType bitValue_ = MachineType::NOVALUE;
GateType type_;
TimeStamp stamp_;
MarkCode mark_;
BitField bitfield_;
GateRef firstOut_;
GateId id_ {0}; // uint32_t
GateType type_; // uint32_t
OpCode opcode_; // uint8_t
MachineType bitValue_ = MachineType::NOVALUE; // uint8_t
TimeStamp stamp_; // uint8_t
MarkCode mark_; // uint8_t
BitField bitfield_; // uint64_t
GateRef firstOut_; // int32_t
// in(0)
// in(1)
// in(2)

View File

@ -77,6 +77,12 @@ void GateAccessor::Print(GateRef gate) const
gatePtr->Print();
}
void GateAccessor::ShortPrint(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
gatePtr->ShortPrint();
}
GateId GateAccessor::GetId(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
@ -210,16 +216,21 @@ bool GateAccessor::IsState(GateRef gate) const
return GetOpCode(gate).IsState();
}
bool GateAccessor::IsConstant(GateRef gate) const
{
return GetOpCode(gate).IsConstant();
}
bool GateAccessor::IsTypedOperator(GateRef gate) const
{
return GetOpCode(gate).IsTypedOperator();
}
bool GateAccessor::IsSchedulable(GateRef gate) const
{
return GetOpCode(gate).IsSchedulable();
}
bool GateAccessor::IsTypedGate(GateRef gate) const
{
return GetOpCode(gate).IsTypedGate();
}
GateRef GateAccessor::GetDep(GateRef gate, size_t idx) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
@ -302,6 +313,12 @@ void GateAccessor::DecreaseIn(const UseIterator &useIt)
circuit_->DecreaseIn(*useIt, idx);
}
void GateAccessor::DecreaseIn(GateRef gate, size_t index)
{
circuit_->DecreaseIn(gate, index);
}
void GateAccessor::NewIn(GateRef gate, size_t idx, GateRef in)
{
circuit_->NewIn(gate, idx, in);
@ -428,4 +445,16 @@ bool GateAccessor::IsValueIn(GateRef gate, size_t index) const
size_t valueEndIndex = valueStartIndex + GetInValueCount(gate);
return (index >= valueStartIndex && index < valueEndIndex);
}
void GateAccessor::DeleteGuardAndFrameState(GateRef gate)
{
GateRef guard = GetDep(gate);
if (GetOpCode(guard) == OpCode::GUARD) {
GateRef dep = GetDep(guard);
ReplaceDependIn(gate, dep);
GateRef frameState = GetValueIn(guard, 1);
DeleteGate(frameState);
DeleteGate(guard);
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -310,6 +310,7 @@ public:
BitField GetBitField(GateRef gate) const;
void SetBitField(GateRef gate, BitField bitField);
void Print(GateRef gate) const;
void ShortPrint(GateRef gate) const;
GateId GetId(GateRef gate) const;
GateRef GetValueIn(GateRef gate, size_t idx = 0) const;
size_t GetNumValueIn(GateRef gate) const;
@ -326,6 +327,7 @@ public:
void DeleteIn(GateRef gate, size_t idx);
UseIterator DeleteGate(const UseIterator &useIt);
void DecreaseIn(const UseIterator &useIt);
void DecreaseIn(GateRef gate, size_t index);
void NewIn(GateRef gate, size_t idx, GateRef in);
size_t GetStateCount(GateRef gate) const;
size_t GetDependCount(GateRef gate) const;
@ -345,8 +347,9 @@ public:
bool IsLoopHead(GateRef gate) const;
bool IsLoopBack(GateRef gate) const;
bool IsState(GateRef gate) const;
bool IsConstant(GateRef gate) const;
bool IsTypedOperator(GateRef gate) const;
bool IsSchedulable(GateRef gate) const;
bool IsTypedGate(GateRef gate) const;
MarkCode GetMark(GateRef gate) const;
void SetMark(GateRef gate, MarkCode mark);
bool IsFinished(GateRef gate) const;
@ -360,6 +363,7 @@ public:
bool IsExceptionState(const UseIterator &useIt) const;
bool IsDependIn(GateRef gate, size_t index) const;
bool IsValueIn(GateRef gate, size_t index) const;
void DeleteGuardAndFrameState(GateRef gate);
private:
ConstUseIterator ConstUseBegin(GateRef gate) const

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 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 <stack>
#include "ecmascript/compiler/circuit_optimizer.h"
#include "ecmascript/compiler/guard_eliminating.h"
#include "ecmascript/compiler/scheduler.h"
namespace panda::ecmascript::kungfu {
bool GuardEliminating::HasGuard(GateRef gate) const
{
if (acc_.IsTypedOperator(gate)) {
auto guard = acc_.GetDep(gate);
auto op = acc_.GetOpCode(guard);
return op == OpCode::GUARD;
}
return false;
}
void GuardEliminating::ProcessTwoConditions(GateRef gate, std::set<GateRef> &conditionSet)
{
auto guard = acc_.GetDep(gate);
auto condition = acc_.GetValueIn(guard, 0);
auto left = acc_.GetValueIn(condition, 0);
auto right = acc_.GetValueIn(condition, 1);
if (left == right) {
acc_.ReplaceValueIn(guard, left, 0);
ProcessOneCondition(gate, conditionSet);
return;
}
if (conditionSet.count(left) > 0 && conditionSet.count(right) > 0) {
acc_.DeleteGuardAndFrameState(gate);
} else if (conditionSet.count(left) > 0) {
acc_.ReplaceValueIn(guard, right, 0);
conditionSet.insert(right);
} else if (conditionSet.count(right) > 0) {
acc_.ReplaceValueIn(guard, left, 0);
conditionSet.insert(left);
} else {
conditionSet.insert(left);
conditionSet.insert(right);
}
}
void GuardEliminating::ProcessOneCondition(GateRef gate, std::set<GateRef> &conditionSet)
{
auto guard = acc_.GetDep(gate);
auto condition = acc_.GetValueIn(guard, 0);
if (conditionSet.count(condition) > 0) {
acc_.DeleteGuardAndFrameState(gate);
} else {
conditionSet.insert(condition);
}
}
void GuardEliminating::RemoveConditionFromSet(GateRef condition, std::set<GateRef> &conditionSet)
{
if (acc_.GetOpCode(condition) == OpCode::AND) {
auto left = acc_.GetValueIn(condition, 0);
auto right = acc_.GetValueIn(condition, 1);
conditionSet.erase(left);
conditionSet.erase(right);
} else {
conditionSet.erase(condition);
}
}
void GuardEliminating::Run()
{
// eliminate duplicate typecheck
GlobalValueNumbering(circuit_).Run();
// calculate dominator tree
std::vector<GateRef> bbGatesList;
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
std::vector<size_t> immDom;
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit_);
std::vector<std::vector<size_t>> domTree(immDom.size(), std::vector<size_t>(0));
for (size_t idx = 1; idx < immDom.size(); ++idx) {
domTree[immDom[idx]].emplace_back(idx);
}
// dfs the dominator tree to eliminate guard
// which is domined by another guard with same condition
std::set<GateRef> conditionSet;
struct DFSState {
size_t curbb;
size_t idx;
};
std::stack<DFSState> dfsStack;
auto startGate = Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY));
DFSState startState = { bbGatesAddrToIdx[startGate], 0 };
dfsStack.push(startState);
while (!dfsStack.empty()) {
auto &curState = dfsStack.top();
auto &curbb = curState.curbb;
auto &idx = curState.idx;
if (idx == domTree[curbb].size()) {
auto curGate = bbGatesList[curbb];
if (HasGuard(curGate)) {
auto guard = acc_.GetDep(curGate);
auto condition = acc_.GetValueIn(guard, 0);
RemoveConditionFromSet(condition, conditionSet);
}
dfsStack.pop();
continue;
}
auto succbb = domTree[curbb][idx];
auto succGate = bbGatesList[succbb];
if (HasGuard(succGate)) {
auto guard = acc_.GetDep(succGate);
auto condition = acc_.GetValueIn(guard, 0);
if (acc_.GetOpCode(condition) == OpCode::AND) {
ProcessTwoConditions(succGate, conditionSet);
} else {
ProcessOneCondition(succGate, conditionSet);
}
}
DFSState newState = { succbb, 0 };
dfsStack.push(newState);
idx++;
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After guard eliminating "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGates(*bcBuilder_);
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 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.
*/
#ifndef ECMASCRIPT_COMPILER_GUARD_ELIMINATING_H
#define ECMASCRIPT_COMPILER_GUARD_ELIMINATING_H
#include "ecmascript/compiler/gate_accessor.h"
namespace panda::ecmascript::kungfu {
class GuardEliminating {
public:
GuardEliminating(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, bool enableLog, const std::string& name)
: bcBuilder_(bcBuilder), circuit_(circuit), acc_(circuit), enableLog_(enableLog), methodName_(name) {}
~GuardEliminating() = default;
void Run();
private:
bool IsLogEnabled() const
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
bool HasGuard(GateRef gate) const;
void ProcessTwoConditions(GateRef gate, std::set<GateRef> &conditionSet);
void ProcessOneCondition(GateRef gate, std::set<GateRef> &conditionSet);
void RemoveConditionFromSet(GateRef condition, std::set<GateRef> &conditionSet);
BytecodeCircuitBuilder *bcBuilder_ {nullptr};
Circuit *circuit_ {nullptr};
GateAccessor acc_;
bool enableLog_ {false};
std::string methodName_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_GUARD_ELIMINATING_H

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 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/compiler/guard_lowering.h"
namespace panda::ecmascript::kungfu {
void GuardLowering::LowerGuard(GateRef gate)
{
GateRef checkGate = acc_.GetIn(gate, 1);
acc_.ReplaceValueIn(gate, builder_.False(), 0);
std::vector<GateRef> outs;
acc_.GetOutVector(gate, outs); // get guard next gate
ASSERT(outs.size() == 1);
GateRef next = outs[0];
GateRef prev = acc_.GetState(next);
GateRef ifBranch = builder_.Branch(prev, checkGate);
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
acc_.ReplaceStateIn(next, ifTrue);
GateRef dep = acc_.GetDep(gate);
acc_.ReplaceDependIn(next, dep);
GateRef relay = builder_.DependRelay(ifFalse, dep);
acc_.ReplaceDependIn(gate, relay);
builder_.Return(ifFalse, gate, gate);
}
void GuardLowering::Run()
{
std::vector<GateRef> gateList;
circuit_->GetAllGates(gateList);
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
if (op == OpCode::GUARD) {
LowerGuard(gate);
}
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After guard lowering "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGates(*bcBuilder_);
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 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.
*/
#ifndef ECMASCRIPT_COMPILER_GUARD_LOWERING_PASS_H
#define ECMASCRIPT_COMPILER_GUARD_LOWERING_PASS_H
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/circuit_builder.h"
namespace panda::ecmascript::kungfu {
class GuardLowering {
public:
GuardLowering(BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg, Circuit *circuit, std::string name,
bool enableLog)
: bcBuilder_(builder), builder_(circuit, cmpCfg), circuit_(circuit),
acc_(circuit), methodName_(name), enableLog_(enableLog) {}
~GuardLowering() = default;
void Run();
private:
bool IsLogEnabled() const
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
void LowerGuard(GateRef gate);
BytecodeCircuitBuilder *bcBuilder_ {nullptr};
CircuitBuilder builder_ {nullptr};
Circuit *circuit_ {nullptr};
GateAccessor acc_;
std::string methodName_;
bool enableLog_ {false};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_GUARD_LOWERING_PASS_H

View File

@ -83,7 +83,8 @@ void LLVMIRGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlo
}
void LLVMIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const panda::ecmascript::MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile)
const panda::ecmascript::MethodLiteral *methodLiteral,
const JSPandaFile *jsPandaFile)
{
auto function = module_->AddFunc(methodLiteral, jsPandaFile);
circuit->SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
@ -187,9 +188,11 @@ void LLVMAssembler::Run(const CompilerLog &log)
{
char *error = nullptr;
std::string originName = llvm::unwrap(module_)->getModuleIdentifier() + ".ll";
std::string optName = llvm::unwrap(module_)->getModuleIdentifier() + "_opt" + ".ll";
std::string optName = llvm::unwrap(module_)->getModuleIdentifier() + "_opt.ll";
if (!log.NoneMethod() && log.OutputLLIR()) {
LLVMPrintModuleToFile(module_, originName.c_str(), &error);
std::string errInfo = (error != nullptr) ? error : "";
LOG_COMPILER(INFO) << "generate " << originName << " " << errInfo;
}
LLVMVerifyModule(module_, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
@ -197,10 +200,13 @@ void LLVMAssembler::Run(const CompilerLog &log)
if (!BuildMCJITEngine()) {
return;
}
llvm::unwrap(engine_)-> setProcessAllSections(true);
llvm::unwrap(engine_)->setProcessAllSections(true);
BuildAndRunPasses();
if (!log.NoneMethod() && log.OutputLLIR()) {
error = nullptr;
LLVMPrintModuleToFile(module_, optName.c_str(), &error);
std::string errInfo = (error != nullptr) ? error : "";
LOG_COMPILER(INFO) << "generate " << optName << " " << errInfo;
}
}
@ -249,6 +255,32 @@ static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_
return nullptr;
}
kungfu::CalleeRegAndOffsetVec LLVMAssembler::GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log)
{
kungfu::CalleeRegAndOffsetVec info;
llvm::Function* func = llvm::unwrap<llvm::Function>(fn);
for (const auto &Attr : func->getAttributes().getFnAttributes()) {
if (Attr.isStringAttribute()) {
std::string str = std::string(Attr.getKindAsString().data());
std::string expectedKey = "DwarfReg";
if (str.size() >= expectedKey.size() &&
str.substr(0, expectedKey.size()) == expectedKey) {
int RegNum = std::stoi(str.substr(expectedKey.size(), str.size() - expectedKey.size()));
auto value = std::stoi(std::string(Attr.getValueAsString()));
info.push_back(std::make_pair(RegNum, value));
(void)log;
auto logFlag = true;
if (logFlag) {
LOG_COMPILER(INFO) << " RegNum:" << RegNum << " value:" << value << std::endl;
}
}
}
}
return info;
}
int LLVMAssembler::GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log)
{
int fpToCallerSpDelta = 0;
@ -311,8 +343,10 @@ void LLVMAssembler::Disassemble(const std::map<uintptr_t, std::string> &addr2nam
logFlag = false;
}
if (logFlag) {
LOG_COMPILER(INFO) << "=======================================================================";
LOG_COMPILER(INFO) << methodName.c_str() << " disassemble:";
LOG_COMPILER(INFO) << "\033[34m"
<< "======================== Generated Asm Code ============================="
<< "\033[0m";
LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << methodName << "]:" << "\033[0m";
}
}

View File

@ -93,9 +93,9 @@ struct CodeInfo {
unreqSecs_ = nullptr;
}
uint8_t *AllocaInReqSecBuffer(uintptr_t size)
uint8_t *AllocaInReqSecBuffer(uintptr_t size, bool alignFlag = true)
{
return Alloca(size, reqSecs_, reqBufPos_);
return Alloca(size, reqSecs_, reqBufPos_, alignFlag);
}
uint8_t *AllocaInNotReqSecBuffer(uintptr_t size)
@ -105,7 +105,8 @@ struct CodeInfo {
uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName)
{
uint8_t *addr = AllocaInReqSecBuffer(size);
// if have got section, don't use align.
uint8_t *addr = AllocaInReqSecBuffer(size, false);
auto curSec = ElfSection(sectionName);
codeInfo_.push_back({addr, size});
if (curSec.isValidAOTSec()) {
@ -181,10 +182,12 @@ private:
std::array<sectionInfo, static_cast<int>(ElfSecName::SIZE)> secInfos_;
std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {}; // info for disasssembler, planed to be deprecated
uint8_t *Alloca(uintptr_t size, uint8_t *bufBegin, size_t &curPos)
uint8_t *Alloca(uintptr_t size, uint8_t *bufBegin, size_t &curPos, bool alignFlag = true)
{
// align up for rodata section
size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
if (alignFlag) {
size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
}
uint8_t *addr = nullptr;
size_t limit = (bufBegin == reqSecs_) ? REQUIRED_SECS_LIMIT : UNREQUIRED_SECS_LIMIT;
if (curPos + size > limit) {
@ -219,6 +222,7 @@ public:
void Disassemble(const std::map<uintptr_t, std::string> &addr2name,
const CompilerLog &log, const MethodLogList &logList) const;
static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log);
static kungfu::CalleeRegAndOffsetVec GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log);
static void Disassemble(uint8_t *buf, size_t size);
uintptr_t GetSectionAddr(ElfSecName sec) const

View File

@ -22,6 +22,7 @@
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/gate.h"
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/frames.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/method.h"
@ -190,12 +191,14 @@ void LLVMIRBuilder::InitializeHandlers()
{OpCode::LSL, &LLVMIRBuilder::HandleIntLsl},
{OpCode::SMOD, &LLVMIRBuilder::HandleMod},
{OpCode::FMOD, &LLVMIRBuilder::HandleMod},
{OpCode::GUARD, &LLVMIRBuilder::HandleGuardCall},
};
illegalOpHandlers_ = {
OpCode::NOP, OpCode::CIRCUIT_ROOT, OpCode::DEPEND_ENTRY,
OpCode::FRAMESTATE_ENTRY, OpCode::RETURN_LIST, OpCode::THROW_LIST,
OpCode::CONSTANT_LIST, OpCode::ARG_LIST, OpCode::THROW,
OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY, OpCode::DEPEND_AND
OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY, OpCode::DEPEND_AND,
OpCode::FRAME_STATE
};
}
@ -232,15 +235,6 @@ void LLVMIRBuilder::Build()
for (size_t instIdx = bb.size(); instIdx > 0; instIdx--) {
GateRef gate = bb[instIdx - 1];
std::vector<GateRef> ins;
acc_.GetInVector(gate, ins);
std::vector<GateRef> outs;
acc_.GetOutVector(gate, outs);
if (IsLogEnabled()) {
acc_.Print(gate);
}
auto found = opHandlers_.find(acc_.GetOpCode(gate));
if (found != opHandlers_.end()) {
(this->*(found->second))(gate);
@ -509,14 +503,17 @@ void LLVMIRBuilder::HandleRuntimeCall(GateRef gate)
}
LLVMValueRef LLVMIRBuilder::GetFunction(LLVMValueRef glue, const CallSignature *signature,
LLVMValueRef rtbaseoffset) const
LLVMValueRef rtbaseoffset, const std::string &realName) const
{
LLVMTypeRef rtfuncType = llvmModule_->GetFuncType(signature);
LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0);
LLVMTypeRef glueType = LLVMTypeOf(glue);
LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(glueType, 0), "");
LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, "");
LLVMValueRef callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, "cast");
std::string name = realName.empty()
? signature->GetName()
: realName;
LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, name.c_str());
LLVMValueRef callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, (name + "-cast").c_str());
ASSERT(callee != nullptr);
return callee;
}
@ -550,11 +547,10 @@ void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &i
LLVMValueRef rtoffset = GetRTStubOffset(glue, stubIndex);
LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
std::vector<LLVMValueRef> params;
params.push_back(glue); // glue
int index = static_cast<int>(acc_.GetBitField(inList[static_cast<int>(CallInputs::TARGET)]));
const int index = static_cast<int>(acc_.GetBitField(inList[static_cast<int>(CallInputs::TARGET)]));
params.push_back(LLVMConstInt(LLVMInt64Type(), index, 0)); // target
params.push_back(LLVMConstInt(LLVMInt64Type(),
inList.size() - static_cast<size_t>(CallInputs::FIRST_PARAMETER), 0)); // argc
@ -564,6 +560,8 @@ void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &i
}
LLVMTypeRef funcType = llvmModule_->GenerateFuncType(params, signature);
std::string targetName = RuntimeStubCSigns::GetRTName(index);
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset, targetName);
callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
LLVMValueRef runtimeCall = LLVMBuildCall2(builder_, funcType, callee, params.data(), inList.size(), "");
if (!compCfg_->Is32Bit()) { // Arm32 not support webkit jscc calling convention
@ -794,9 +792,8 @@ void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList,
auto bcIndex = LLVMConstInt(LLVMInt64Type(), static_cast<int>(SpecVregIndex::BC_OFFSET_INDEX), 1);
values.push_back(bcIndex);
values.push_back(bcOffset);
call = LLVMBuildCall3(
builder_, funcType, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt, "", values.data(),
values.size());
call = LLVMBuildCall3(builder_, funcType, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt,
"", values.data(), values.size());
} else {
call = LLVMBuildCall2(builder_, funcType, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt,
"");
@ -1853,6 +1850,57 @@ void LLVMIRBuilder::VisitBitCast(GateRef gate, GateRef e1)
gate2LValue_[gate] = result;
}
void LLVMIRBuilder::HandleGuardCall(GateRef gate)
{
VisitGuardCall(gate);
}
LLVMTypeRef LLVMIRBuilder::GetExperimentalDeoptTy()
{
auto fnTy = LLVMFunctionType(LLVMPointerType(LLVMInt64Type(), 1), nullptr, 0, 1);
return fnTy;
}
LLVMValueRef LLVMIRBuilder::GetExperimentalDeopt(LLVMModuleRef &module)
{
/* 0:calling 1:its caller */
auto fn = LLVMGetNamedFunction(module, "llvm.experimental.deoptimize.p1i64");
if (!fn) {
auto fnTy = GetExperimentalDeoptTy();
fn = LLVMAddFunction(module, "llvm.experimental.deoptimize.p1i64", fnTy);
}
return fn;
}
void LLVMIRBuilder::VisitGuardCall(GateRef gate)
{
LLVMValueRef glue = gate2LValue_.at(acc_.GetIn(gate, 3));
GateRef frameState = acc_.GetIn(gate, 2);
std::vector<LLVMValueRef> params;
params.push_back(glue); // glue
LLVMValueRef callee = GetExperimentalDeopt(module_);
LLVMTypeRef funcType = GetExperimentalDeoptTy();
const size_t numValueIn = acc_.GetBitField(frameState);
const size_t accIndex = numValueIn - 2; // 2: acc valueIn index
const size_t pcIndex = numValueIn - 1;
GateRef acc = acc_.GetValueIn(frameState, accIndex);
GateRef pc = acc_.GetValueIn(frameState, pcIndex);
std::vector<LLVMValueRef> values;
for (size_t i = 0; i < accIndex; i++) {
GateRef vreg = acc_.GetValueIn(frameState, i);
values.emplace_back(LLVMConstInt(LLVMInt32Type(), i, false));
values.emplace_back(gate2LValue_.at(vreg));
}
values.emplace_back(LLVMConstInt(LLVMInt32Type(), static_cast<int>(SpecVregIndex::ACC_INDEX), false));
values.emplace_back(gate2LValue_.at(acc));
values.emplace_back(LLVMConstInt(LLVMInt32Type(), static_cast<int>(SpecVregIndex::PC_INDEX), false));
values.emplace_back(gate2LValue_.at(pc));
LLVMValueRef runtimeCall =
LLVMBuildCall3(builder_, funcType, callee, params.data(), params.size(), "", values.data(), values.size());
gate2LValue_[gate] = runtimeCall;
}
LLVMModule::LLVMModule(const std::string &name, const std::string &triple)
: cfg_(triple)
{
@ -1982,9 +2030,13 @@ LLVMValueRef LLVMModule::AddFunc(const panda::ecmascript::MethodLiteral *methodL
auto numOfRestArgs = paramCount - funcIndex;
paramTys.insert(paramTys.end(), numOfRestArgs, NewLType(MachineType::I64, GateType::TaggedValue()));
auto funcType = LLVMFunctionType(returnType, paramTys.data(), paramCount, false); // not variable args
const char *name = MethodLiteral::GetMethodName(jsPandaFile, methodLiteral->GetMethodId());
auto function = LLVMAddFunction(module_, name, funcType);
auto offsetInPandaFile = methodLiteral->GetMethodId().GetOffset();
std::string fileName = jsPandaFile->GetFileName();
std::string name = MethodLiteral::GetMethodName(jsPandaFile, methodLiteral->GetMethodId());
name += std::string("@") + std::to_string(offsetInPandaFile) + std::string("@") + fileName;
auto function = LLVMAddFunction(module_, name.c_str(), funcType);
SetFunction(offsetInPandaFile, function);
return function;
}

View File

@ -228,7 +228,8 @@ private:
V(IntLsl, (GateRef gate, GateRef e1, GateRef e2)) \
V(Mod, (GateRef gate, GateRef e1, GateRef e2)) \
V(ChangeTaggedPointerToInt64, (GateRef gate, GateRef e1)) \
V(ChangeInt64ToTagged, (GateRef gate, GateRef e1))
V(ChangeInt64ToTagged, (GateRef gate, GateRef e1)) \
V(GuardCall, (GateRef gate))
// runtime/common stub ID, opcodeOffset for bc stub
using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>;
@ -292,7 +293,8 @@ private:
{
return enableLog_;
}
LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset) const;
LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset,
const std::string &realName = "") const;
LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature,
LLVMValueRef reloc) const;
bool IsInterpreted();
@ -320,6 +322,8 @@ private:
void ComputeArgCountAndBCOffset(size_t &actualNumArgs, LLVMValueRef &bcOffset, const std::vector<GateRef> &inList,
OpCode op);
void SaveLexicalEnvOnFrame(LLVMValueRef value);
LLVMTypeRef GetExperimentalDeoptTy();
LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module);
const CompilationConfig *compCfg_ {nullptr};
const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
const Circuit *circuit_ {nullptr};

View File

@ -19,6 +19,8 @@
#include "ecmascript/compiler/async_function_lowering.h"
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/guard_eliminating.h"
#include "ecmascript/compiler/guard_lowering.h"
#include "ecmascript/compiler/llvm_codegen.h"
#include "ecmascript/compiler/scheduler.h"
#include "ecmascript/compiler/slowpath_lowering.h"
@ -30,8 +32,11 @@
namespace panda::ecmascript::kungfu {
class PassData {
public:
explicit PassData(Circuit *circuit, const CompilerLog *log, bool enableMethodLog)
: circuit_(circuit), log_(log), enableMethodLog_(enableMethodLog) {}
explicit PassData(Circuit *circuit, const CompilerLog *log, bool enableMethodLog, std::string name)
: circuit_(circuit), log_(log), enableMethodLog_(enableMethodLog), name_(name)
{
}
virtual ~PassData() = default;
const ControlFlowGraph &GetScheduleResult() const
{
@ -58,11 +63,17 @@ public:
return enableMethodLog_;
}
const std::string& GetMethodName() const
{
return name_;
}
private:
Circuit *circuit_ {nullptr};
ControlFlowGraph cfg_;
const CompilerLog *log_ {nullptr};
bool enableMethodLog_ {false};
std::string name_;
};
template<typename T1>
@ -89,7 +100,7 @@ public:
if (builder->HasTypes()) {
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputType();
TypeInfer typeInfer(builder, data->GetCircuit(), constantPool, tsManager,
lexEnvManager, methodId, enableLog);
lexEnvManager, methodId, enableLog, data->GetMethodName());
typeInfer.TraverseCircuit();
}
return true;
@ -101,7 +112,7 @@ public:
bool Run(PassData *data, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg, TSManager *tsManager)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
TSTypeLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog);
TSTypeLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog, data->GetMethodName());
if (builder->HasTypes()) {
lowering.RunTSTypeLowering();
}
@ -114,7 +125,7 @@ public:
bool Run(PassData *data, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg, TSManager *tsManager)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
TypeLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog);
TypeLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog, data->GetMethodName());
if (builder->HasTypes()) {
lowering.RunTypeLowering();
}
@ -127,7 +138,7 @@ public:
bool Run(PassData* data, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg, TSManager *tsManager)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
SlowPathLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog);
SlowPathLowering lowering(builder, data->GetCircuit(), cmpCfg, tsManager, enableLog, data->GetMethodName());
lowering.CallRuntimeLowering();
return true;
}
@ -138,7 +149,7 @@ public:
bool Run(PassData* data)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
bool isQualified = Verifier::Run(data->GetCircuit(), enableLog);
bool isQualified = Verifier::Run(data->GetCircuit(), data->GetMethodName(), enableLog);
if (!isQualified) {
LOG_FULL(FATAL) << "VerifierPass fail";
UNREACHABLE();
@ -147,12 +158,22 @@ public:
}
};
class GuardEliminatingPass {
public:
bool Run(PassData* data, BytecodeCircuitBuilder *builder)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
GuardEliminating(builder, data->GetCircuit(), enableLog, data->GetMethodName()).Run();
return true;
}
};
class SchedulingPass {
public:
bool Run(PassData* data)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
data->SetScheduleResult(Scheduler::Run(data->GetCircuit(), enableLog));
data->SetScheduleResult(Scheduler::Run(data->GetCircuit(), data->GetMethodName(), enableLog));
return true;
}
};
@ -164,12 +185,12 @@ public:
llvmImpl_ = std::make_unique<LLVMIRGeneratorImpl>(module, enableLog);
}
bool Run(PassData *data, LLVMModule *module,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile)
bool Run(PassData *data, LLVMModule *module, const MethodLiteral *methodLiteral,
const JSPandaFile *jsPandaFile)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
CreateCodeGen(module, enableLog);
CodeGenerator codegen(llvmImpl_);
CodeGenerator codegen(llvmImpl_, data->GetMethodName());
codegen.Run(data->GetCircuit(), data->GetScheduleResult(), module->GetCompilationConfig(),
methodLiteral, jsPandaFile);
return true;
@ -183,12 +204,22 @@ public:
bool Run(PassData* data, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
AsyncFunctionLowering lowering(builder, data->GetCircuit(), cmpCfg, enableLog);
AsyncFunctionLowering lowering(builder, data->GetCircuit(), cmpCfg, enableLog, data->GetMethodName());
if (lowering.IsAsyncRelated()) {
lowering.ProcessAll();
}
return true;
}
};
class GuardLoweringPass {
public:
bool Run(PassData* data, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
GuardLowering(builder, cmpCfg, data->GetCircuit(), data->GetMethodName(), enableLog).Run();
return true;
}
};
} // namespace panda::ecmascript::kungfu
#endif

View File

@ -36,7 +36,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
auto constantPool = CreateConstPool(jsPandaFile);
DecodeTSTypes(jsPandaFile, fileName);
auto aotModule = new LLVMModule("aot_" + fileName, triple_);
auto aotModule = new LLVMModule(fileName, triple_);
auto aotModuleAssembler = new LLVMAssembler(aotModule->GetModule(),
LOptions(optLevel_, true, relocMode_));
CompilationConfig cmpCfg(triple_, log_->IsEnableByteCodeTrace());
@ -63,20 +63,22 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
enableMethodLog = logList_->IncludesMethod(fileName, methodName);
}
std::string fullName = methodName + "@" + fileName;
if (enableMethodLog) {
LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fileName << ":"
<< methodName << "] log:" << "\033[0m";
LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName << "] log:" << "\033[0m";
}
BytecodeCircuitBuilder builder(jsPandaFile, method, methodPCInfo, tsManager,
&cmpCfg, enableMethodLog && log_->OutputCIR());
&cmpCfg, enableMethodLog && log_->OutputCIR(), fullName);
builder.BytecodeToCircuit();
PassData data(builder.GetCircuit(), log_, enableMethodLog);
PassData data(builder.GetCircuit(), log_, enableMethodLog, fullName);
PassRunner<PassData> pipeline(&data);
pipeline.RunPass<TypeInferPass>(&builder, constantPool, tsManager, &lexEnvManager, methodInfoId);
pipeline.RunPass<AsyncFunctionLoweringPass>(&builder, &cmpCfg);
if (EnableTypeLowering()) {
pipeline.RunPass<TSTypeLoweringPass>(&builder, &cmpCfg, tsManager);
pipeline.RunPass<GuardEliminatingPass>(&builder);
pipeline.RunPass<GuardLoweringPass>(&builder, &cmpCfg);
pipeline.RunPass<TypeLoweringPass>(&builder, &cmpCfg, tsManager);
}
pipeline.RunPass<SlowPathLoweringPass>(&builder, &cmpCfg, tsManager);
@ -84,6 +86,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
pipeline.RunPass<SchedulingPass>();
pipeline.RunPass<LLVMIRGenPass>(aotModule, method, jsPandaFile);
});
LOG_COMPILER(INFO) << " ";
LOG_COMPILER(INFO) << skippedMethodNum << " large methods in " << fileName << " have been skipped";
generator.AddModule(aotModule, aotModuleAssembler, jsPandaFile);
return true;
@ -108,7 +111,8 @@ JSPandaFile *PassManager::ResolveModuleFile(JSPandaFile *jsPandaFile, const std:
JSThread *thread = vm_->GetJSThread();
ModuleManager *moduleManager = vm_->GetModuleManager();
CString moduleFileName = moduleManager->ResolveModuleFileName(fileName.c_str());
return const_cast<JSPandaFile *>(JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, moduleFileName,
return const_cast<JSPandaFile *>(JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread,
moduleFileName,
entry_));
}
return jsPandaFile;

View File

@ -24,21 +24,26 @@ CallSignature RuntimeStubCSigns::callSigns_[RuntimeStubCSigns::NUM_OF_RTSTUBS_WI
void RuntimeStubCSigns::Initialize()
{
#define INIT_SIGNATURES(name) \
name##CallSignature::Initialize(&callSigns_[ID_##name]); \
callSigns_[ID_##name].SetID(ID_##name); \
assert(callSigns_[ID_##name].IsRuntimeNGCStub() || \
callSigns_[ID_##name].IsRuntimeStub() || \
#define INIT_SIGNATURES(name) \
name##CallSignature::Initialize(&callSigns_[ID_##name]); \
callSigns_[ID_##name].SetName(std::string("RTStub_") + #name); \
callSigns_[ID_##name].SetID(ID_##name); \
assert(callSigns_[ID_##name].IsRuntimeNGCStub() || \
callSigns_[ID_##name].IsRuntimeStub() || \
callSigns_[ID_##name].IsDeoptStub() || \
callSigns_[ID_##name].IsRuntimeVAStub());
RUNTIME_STUB_WITHOUT_GC_LIST(INIT_SIGNATURES)
RUNTIME_ASM_STUB_LIST(INIT_SIGNATURES)
#undef INIT_SIGNATURES
#define INIT_ASM_SIGNATURES(name) \
callSigns_[RuntimeStubCSigns::ID_##name].SetConstructor( \
[]([[maybe_unused]]void* arg) { \
return static_cast<void*>(new name##Stub()); \
#define INIT_ASM_SIGNATURES(name) \
callSigns_[RuntimeStubCSigns::ID_##name].SetName(std::string("RTStub_") + #name); \
callSigns_[RuntimeStubCSigns::ID_##name].SetConstructor( \
[]([[maybe_unused]]void* arg) { \
return static_cast<void*>(new name##Stub()); \
});
RUNTIME_ASM_STUB_LIST(INIT_ASM_SIGNATURES)
#undef INIT_ASM_SIGNATURES
}

View File

@ -46,6 +46,20 @@ public:
ASSERT(index < NUM_OF_RTSTUBS_WITHOUT_GC);
return &callSigns_[index];
}
static std::string GetRTName(int index)
{
ASSERT(index < NUM_OF_STUBS);
switch (index) {
#define DEF_STUB_NAME(name) case ID_##name: { return std::string("RTStub_") + #name; }
RUNTIME_STUB_LIST(DEF_STUB_NAME)
#undef DEF_STUB_NAME
default:
return "unknown";
}
return "unknown";
}
private:
static CallSignature callSigns_[NUM_OF_RTSTUBS_WITHOUT_GC];
};

View File

@ -114,10 +114,12 @@ DominatorTreeInfo Scheduler::CalculateDominatorTree(const Circuit *circuit)
return {bbGatesList, bbGatesAddrToIdx, immDom};
}
std::vector<std::vector<GateRef>> Scheduler::Run(const Circuit *circuit, [[maybe_unused]] bool enableLog)
std::vector<std::vector<GateRef>> Scheduler::Run(const Circuit *circuit,
[[maybe_unused]] const std::string& methodName,
[[maybe_unused]] bool enableLog)
{
#ifndef NDEBUG
if (!Verifier::Run(circuit, enableLog)) {
if (!Verifier::Run(circuit, methodName, enableLog)) {
UNREACHABLE();
}
#endif
@ -435,9 +437,9 @@ void Scheduler::Print(const std::vector<std::vector<GateRef>> *cfg, const Circui
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
std::vector<size_t> immDom;
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit);
LOG_COMPILER(INFO) << "==========================================================================";
LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
for (size_t bbIdx = 0; bbIdx < cfg->size(); bbIdx++) {
LOG_COMPILER(INFO) << "BB_" << bbIdx << "_" << acc.GetOpCode((*cfg)[bbIdx].front()).Str() << ":"
LOG_COMPILER(INFO) << "B" << bbIdx << "_" << acc.GetOpCode((*cfg)[bbIdx].front()).Str() << ":"
<< " immDom=" << immDom[bbIdx];
LOG_COMPILER(INFO) << " pred=[";
bool isFirst = true;
@ -464,6 +466,6 @@ void Scheduler::Print(const std::vector<std::vector<GateRef>> *cfg, const Circui
acc.Print((*cfg)[bbIdx][instIdx - 1]);
}
}
LOG_COMPILER(INFO) << "==========================================================================";
LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
}
} // namespace panda::ecmascript::kungfu

View File

@ -19,18 +19,24 @@
#include "ecmascript/compiler/circuit.h"
namespace panda::ecmascript::kungfu {
using ControlFlowGraph = std::vector<std::vector<GateRef>>;
class Scheduler {
public:
using ControlFlowGraph = std::vector<std::vector<GateRef>>;
static std::tuple<std::vector<GateRef>, std::unordered_map<GateRef, size_t>, std::vector<size_t>>
CalculateDominatorTree(const Circuit *circuit);
static ControlFlowGraph Run(const Circuit *circuit, bool enableLog = false);
static ControlFlowGraph Run(const Circuit *circuit, [[maybe_unused]] const std::string& methodName = "",
bool enableLog = false);
static std::optional<std::unordered_map<GateRef, size_t>> CalculateSchedulingUpperBound(const Circuit *circuit,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
const std::function<bool(size_t, size_t)> &isAncestor, const std::vector<GateRef> &schedulableGatesList);
static std::optional<std::unordered_map<GateRef, size_t>> CalculateSchedulingLowerBound(const Circuit *circuit,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor, std::vector<GateRef> *order = nullptr);
static void Print(const ControlFlowGraph *cfg, const Circuit *circuit);
};
}; // namespace panda::ecmascript::kungfu

View File

@ -49,8 +49,13 @@ void SlowPathLowering::CallRuntimeLowering()
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "=========================================================";
LOG_COMPILER(INFO) << " ";
LOG_COMPILER(INFO) << "\033[34m" << "================="
<< " After slowpath Lowering "
<< "[" << GetMethodName() << "] "
<< "=================" << "\033[0m";
circuit_->PrintAllGates(*bcBuilder_);
LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
}
}
@ -89,7 +94,7 @@ void SlowPathLowering::ReplaceHirToSubCfg(GateRef hir, GateRef outir,
{
if (outir != Circuit::NullGate()) {
auto type = acc_.GetGateType(hir);
if (type.IsTSType()) {
if (!type.IsAnyType()) {
acc_.SetGateType(outir, type);
}
}
@ -3029,7 +3034,7 @@ void SlowPathLowering::LowerDefineClassWithBuffer(GateRef gate, GateRef glue, Ga
result = LowerCallRuntime(glue, RTSTUB_ID(CreateClassWithBuffer), args, true);
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_EXCEPTION), &isException, &isNotException);
} else {
GlobalTSTypeRef gt = GlobalTSTypeRef(type.GetType());
GlobalTSTypeRef gt = type.GetGTRef();
const std::map<GlobalTSTypeRef, uint32_t> &classTypeIhcIndexMap = tsManager_->GetClassTypeIhcIndexMap();
GateRef ihcIndex = builder_.Int32((classTypeIhcIndexMap.at(gt)));
GateRef ihclass = GetObjectFromConstPool(glue, jsFunc, ihcIndex, ConstPoolType::CLASS_LITERAL);

View File

@ -110,12 +110,12 @@ namespace panda::ecmascript::kungfu {
class SlowPathLowering {
public:
SlowPathLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit,
CompilationConfig *cmpCfg, TSManager *tsManager, bool enableLog)
SlowPathLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, CompilationConfig *cmpCfg,
TSManager *tsManager, bool enableLog, const std::string& name)
: tsManager_(tsManager), bcBuilder_(bcBuilder), circuit_(circuit), acc_(circuit),
argAcc_(circuit), builder_(circuit, cmpCfg),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))),
enableLog_(enableLog)
enableLog_(enableLog), methodName_(name)
{
enableBcTrace_ = cmpCfg->IsEnableByteCodeTrace();
}
@ -133,6 +133,11 @@ public:
}
private:
const std::string& GetMethodName() const
{
return methodName_;
}
GateAccessor::UseIterator ReplaceHirControlGate(const GateAccessor::UseIterator &useIt, GateRef newGate,
bool noThrow = false);
void ReplaceHirToSubCfg(GateRef hir, GateRef outir,
@ -295,6 +300,7 @@ private:
GateRef dependEntry_;
bool enableLog_ {false};
bool enableBcTrace_ {false};
std::string methodName_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_SLOWPATH_LOWERING_H

View File

@ -34,7 +34,7 @@ namespace panda::ecmascript::kungfu {
class StubPassData : public PassData {
public:
explicit StubPassData(Stub *stub, LLVMModule *module, const CompilerLog *log, bool enableMethodLog)
: PassData(nullptr, log, enableMethodLog), module_(module), stub_(stub) {}
: PassData(nullptr, log, enableMethodLog, "stubs"), module_(module), stub_(stub) {}
~StubPassData() = default;
const CompilationConfig *GetCompilationConfig() const
@ -85,7 +85,7 @@ public:
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
auto stubModule = data->GetStubModule();
CreateCodeGen(stubModule, enableLog);
CodeGenerator codegen(llvmImpl_);
CodeGenerator codegen(llvmImpl_, "stubs");
codegen.RunForStub(data->GetCircuit(), data->GetScheduleResult(), index, data->GetCompilationConfig());
return true;
}

View File

@ -51,7 +51,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypeCheckFramework)
builder.Return(entry, depend, check);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false, "TypeCheckFramework");
typeLowering.RunTypeLowering();
EXPECT_TRUE(Verifier::Run(&circuit));
}
@ -67,11 +67,11 @@ HWTEST_F_L0(LoweringRelateGateTests, TypedBinaryOperatorAddFramework)
auto arg1 = builder.Arguments(1);
auto nadd = builder.TypedBinaryOperator(MachineType::I64, TypedBinOp::TYPED_ADD,
GateType::NumberType(), GateType::NumberType(),
{entry, depend, arg0, arg1});
{entry, depend, arg0, arg1}, GateType::NumberType());
builder.Return(nadd, nadd, nadd);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false, "TypedBinaryOperatorAddFramework");
typeLowering.RunTypeLowering();
EXPECT_TRUE(Verifier::Run(&circuit));
}
@ -87,11 +87,11 @@ HWTEST_F_L0(LoweringRelateGateTests, TypedBinaryOperatorLessFramework)
auto arg1 = builder.Arguments(1);
auto nless = builder.TypedBinaryOperator(MachineType::I64, TypedBinOp::TYPED_LESS,
GateType::NumberType(), GateType::NumberType(),
{entry, depend, arg0, arg1});
{entry, depend, arg0, arg1}, GateType::BooleanType());
builder.Return(nless, nless, nless);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false, "TypedBinaryOperatorLessFramework");
typeLowering.RunTypeLowering();
EXPECT_TRUE(Verifier::Run(&circuit));
}
@ -109,7 +109,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypeConvertFramework)
builder.Return(convert, convert, convert);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false, "TypeConvertFramework");
typeLowering.RunTypeLowering();
EXPECT_TRUE(Verifier::Run(&circuit));
}
@ -126,7 +126,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypeOpCodeFramework)
Label exit(&builder);
VariableType arg1Type(MachineType::I64, GateType::BooleanType());
CompilationConfig config("x86_64-unknown-linux-gnu", false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false);
TypeLowering typeLowering(nullptr, &circuit, &config, nullptr, false, "TypeOpCodeFramework");
auto arg0 = builder.Arguments(0);
auto arg1 = builder.Arguments(1);

View File

@ -136,14 +136,6 @@ void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallM
__ Mov(Register(SP), tempRegister);
}
if (kungfu::AssemblerModule::IsCallNew(mode)) {
Register thisRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
[[maybe_unused]] TempRegister1Scope scope(assembler);
Register tempArgcRegister = __ TempRegister1();
__ PushArgc(argcRegister, tempArgcRegister, currentSlotRegister);
__ Str(thisRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
}
Register declaredNumArgsRegister = __ AvailableRegister2();
GetDeclaredNumArgsFromCallField(assembler, callFieldRegister, declaredNumArgsRegister);
@ -1038,7 +1030,8 @@ void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOve
// FP - sp
// X20 - callTarget
// X21 - method
void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister)
void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
Register newSpRegister, Register accRegister)
{
Register glueRegister = __ GlueRegister();
Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
@ -1048,7 +1041,11 @@ void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcR
__ Mov(Register(X19), glueRegister);
}
__ Ldrh(Register(X24, W), MemoryOperand(methodRegister, Method::LITERAL_INFO_OFFSET));
__ Mov(Register(X23), Immediate(JSTaggedValue::VALUE_HOLE));
if (accRegister == INVALID_REG) {
__ Mov(Register(X23), Immediate(JSTaggedValue::VALUE_HOLE));
} else {
ASSERT(accRegister == Register(X23));
}
__ Ldr(Register(X22), MemoryOperand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET));
__ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
__ Mov(Register(X20), pcRegister);
@ -1218,7 +1215,9 @@ void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue,
Register fp, Register op)
{
__ Mov(Register(SP), fp);
if (fp != Register(SP)) {
__ Mov(Register(SP), fp);
}
__ Mov(op, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException));
// 3 : 3 means *8
__ Add(op, glue, Operand(op, LSL, 3));

View File

@ -82,7 +82,10 @@ public:
static void ConstructorJSCallWithArgV(ExtendedAssembler *assembler);
static void DeoptHandlerAsm(ExtendedAssembler *assembler);
private:
static void DeoptEnterAsmInterp(ExtendedAssembler *assembler);
static void JSCallCheck(ExtendedAssembler *assembler, Register jsfunc, Register taggedValue,
Label *nonCallable, Label *notJSFunction);
static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register sp);
@ -168,7 +171,8 @@ private:
static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow);
static void DispatchCall(ExtendedAssembler *assembler, Register pc, Register newSp);
static void DispatchCall(ExtendedAssembler *assembler, Register pc, Register newSp,
Register acc = INVALID_REG);
static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode);

View File

@ -19,6 +19,7 @@
#include "ecmascript/compiler/argument_accessor.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/ecma_runtime_call_info.h"
#include "ecmascript/frames.h"
#include "ecmascript/js_function.h"
@ -456,9 +457,8 @@ void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc
Register frameType(X6);
__ SaveFpAndLr();
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME)));
__ Mov(Register(X5), Immediate(0));
// 2 : 2 means pair
__ Stp(Register(X5), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
__ Stp(Register(Zero), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
Register argC(X5);
Register runtimeId(X6);
__ Mov(argC, Immediate(0));
@ -955,5 +955,111 @@ void OptimizedCall::ConstructorJSCallWithArgV([[maybe_unused]]ExtendedAssembler
PopOptimizedUnfoldArgVFrame(assembler);
__ Ret();
}
void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
{
// rdi
Register glueRegister = __ GlueRegister();
Register context(X2);
Register opRegister(X9);
Register outputCount(X10);
Register frameStateBase(X11);
Register currentSlotRegister(X12);
Register sp(SP);
__ PushFpAndLr();
__ Mov(currentSlotRegister, sp);
__ Ldr(outputCount, MemoryOperand(context, AsmStackContext::GetOutputCountOffset(false)));
__ Add(frameStateBase, context, Immediate(AsmStackContext::GetSize(false)));
Label stackOverflow;
// update fp
__ Str(currentSlotRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
PushArgsWithArgv(assembler, glueRegister, outputCount, frameStateBase, opRegister,
currentSlotRegister, nullptr, &stackOverflow);
Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
{
// X19, fp, x20, x21, x22, x23, x24
// glue sp pc constpool profile acc hotness
__ Ldr(callTargetRegister, MemoryOperand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)));
__ Ldr(Register(X20), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)));
__ Ldr(Register(X23), MemoryOperand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)));
__ Ldr(methodRegister, MemoryOperand(callTargetRegister, JSFunctionBase::METHOD_OFFSET));
__ Add(opRegister, currentSlotRegister, Immediate(AsmInterpretedFrame::GetSize(false)));
__ Align16(currentSlotRegister);
__ Mov(Register(SP), currentSlotRegister);
AsmInterpreterCall::DispatchCall(assembler, Register(X20), opRegister, Register(X23));
}
__ Bind(&stackOverflow);
{
Register temp(X1);
AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(
assembler, glueRegister, sp, temp);
}
}
void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
{
__ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
__ PushFpAndLr();
Register sp(SP);
Register fp(FP);
Register frameType(X1);
Register glueReg(X0);
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
__ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
__ CalleeSave();
Register runtimeId(X2);
__ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
__ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
__ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE)); // 2: skip runtimeId argc
Register ret(X0);
Label stackOverflow;
__ Cmp(ret, Immediate(JSTaggedValue::VALUE_EXCEPTION));
__ B(Condition::EQ, &stackOverflow);
__ CalleeRestore();
Register context(X2);
__ Mov(context, Register(X0));
__ Ldr(glueReg, MemoryOperand(sp, 0));
Label target;
Register temp(X1);
__ Ldr(fp, MemoryOperand(context, AsmStackContext::GetCallerFpOffset(false)));
__ Ldr(temp, MemoryOperand(context, AsmStackContext::GetCallFrameTopOffset(false)));
__ Mov(sp, temp);
__ Ldr(Register(X30), MemoryOperand(context, AsmStackContext::GetReturnAddressOffset(false)));
PushAsmInterpBridgeFrame(assembler);
__ Bl(&target);
PopAsmInterpBridgeFrame(assembler);
__ Ret();
__ Bind(&target);
DeoptEnterAsmInterp(assembler);
__ Bind(&stackOverflow);
{
__ Mov(runtimeId, Immediate(RTSTUB_ID(ThrowStackOverflowException)));
// 2 : 2 means pair
__ Stp(runtimeId, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
__ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE)); // 2: skip runtimeId argc
__ CalleeRestore();
__ RestoreFpAndLr();
__ Ret();
}
}
#undef __
} // panda::ecmascript::aarch64

View File

@ -106,8 +106,7 @@ void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *as
contextRegister, pcRegister, tempRegister);
// call bc stub
CallBCStub(assembler, newSpRegister, glueRegister, callTargetRegister, methodRegister, pcRegister);
DispatchCall(assembler, pcRegister, newSpRegister, callTargetRegister, methodRegister);
__ Bind(&stackOverflow);
{
ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, tempRegister);
@ -243,33 +242,6 @@ void AsmInterpreterCall::PopAsmInterpEntryFrame(ExtendedAssembler *assembler)
}
}
void AsmInterpreterCall::CallBCStub(ExtendedAssembler *assembler, Register newSpRegister, Register glueRegister,
Register callTargetRegister, Register methodRegister, Register pcRegister)
{
Label alignedJSCallEntry;
// align 16 bytes
__ Testb(15, rsp); // 15: 0x1111
__ Jnz(&alignedJSCallEntry);
__ PushAlignBytes();
__ Bind(&alignedJSCallEntry);
{
// prepare call entry
__ Movq(glueRegister, r13); // %r13 - glue
__ Movq(newSpRegister, rbp); // %rbp - sp
// %r12 - pc
__ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx); // rbx - constantpool
__ Movq(Operand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET), r14); // r14 - profileTypeInfo
__ Movq(JSTaggedValue::Hole().GetRawData(), rsi); // rsi - acc
__ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi); // rdi - hotnessCounter
// call the first bytecode handler
__ Movzbq(Operand(pcRegister, 0), rax);
__ Movq(Operand(r13, rax, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)), r11);
__ Jmp(r11);
// fall through
}
}
void AsmInterpreterCall::GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
Register declaredNumArgsRegister)
{
@ -673,7 +645,7 @@ void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOve
Register thisRegister = __ AvailableRegister2();
Label pushFrameState;
Label dispatchCall;
[[maybe_unused]] TempRegisterScope scope(assembler);
Register tempRegister = __ TempRegister();
// args register can reused now.
@ -693,45 +665,51 @@ void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler, Label *stackOve
PushFrameState(assembler, prevSpRegister, fpRegister,
callTargetRegister, thisRegister, methodRegister, pcRegister, tempRegister);
// align 16 bytes
__ Testq(15, rsp); // 15: low 4 bits must be 0b0000
__ Jnz(&dispatchCall);
__ PushAlignBytes();
// fall through
}
__ Bind(&dispatchCall);
{
DispatchCall(assembler, pcRegister, newSpRegister);
}
DispatchCall(assembler, pcRegister, newSpRegister, callTargetRegister, methodRegister);
}
// Input: %r13 - glue
// %rbp - sp
// %r12 - callTarget
// %rbx - method
void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister)
void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
Register newSpRegister, Register callTargetRegister, Register methodRegister,
Register accRegister)
{
Register glueRegister = __ GlueRegister();
// may r12 or rsi
Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
// may rbx or rdx, and pc may rsi or r8, newSp is rdi or r9
Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
__ Movq(Operand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET), r14); // profileTypeInfo: r14
Label dispatchCall;
// align 16 bytes
__ Testq(15, rsp); // 15: low 4 bits must be 0b0000
__ Jnz(&dispatchCall);
__ PushAlignBytes();
__ Bind(&dispatchCall);
// profileTypeInfo: r14
__ Movq(Operand(callTargetRegister, JSFunction::PROFILE_TYPE_INFO_OFFSET), r14);
// glue may rdi
if (glueRegister != r13) {
__ Movq(glueRegister, r13);
}
__ Movq(newSpRegister, rbp); // sp: rbp
__ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi); // hotnessCounter: rdi
__ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx); // constantPool: rbx
__ Movq(pcRegister, r12); // pc: r12
// sp: rbp
__ Movq(newSpRegister, rbp);
// hotnessCounter: rdi
__ Movzwq(Operand(methodRegister, Method::LITERAL_INFO_OFFSET), rdi);
// constantPool: rbx
__ Movq(Operand(methodRegister, Method::CONSTANT_POOL_OFFSET), rbx);
// pc: r12
if (pcRegister != r12) {
__ Movq(pcRegister, r12);
}
Register bcIndexRegister = rax;
Register tempRegister = __ AvailableRegister1();
__ Movzbq(Operand(pcRegister, 0), bcIndexRegister);
// callTargetRegister may rsi
__ Movq(JSTaggedValue::Hole().GetRawData(), rsi); // acc: rsi
// acc: rsi
if (accRegister != rInvalid) {
ASSERT(accRegister == rsi);
} else {
__ Movq(JSTaggedValue::Hole().GetRawData(), rsi);
}
__ Movq(Operand(r13, bcIndexRegister, Times8, JSThread::GlueData::GetBCStubEntriesOffset(false)), tempRegister);
__ Jmp(tempRegister);
}
@ -1149,26 +1127,6 @@ void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembl
__ Ret();
}
void AsmInterpreterCall::PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
Register argv, Register op1, Register op2, Label *stackOverflow)
{
ASSERT(stackOverflow != nullptr);
StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
Register opArgc = argc;
Register op = op1;
if (op1 != op2) {
// use op2 as opArgc and will not change argc register
opArgc = op2;
__ Movq(argc, opArgc);
}
Label loopBeginning;
__ Bind(&loopBeginning);
__ Movq(Operand(argv, opArgc, Times8, -FRAME_SLOT_SIZE), op); // 8: 8 bytes
__ Pushq(op);
__ Subq(1, opArgc);
__ Ja(&loopBeginning);
}
void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
Register op1, Register op2, Label *stackOverflow)
{
@ -1177,32 +1135,12 @@ void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *a
PushUndefinedWithArgc(assembler, argc);
}
void AsmInterpreterCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
Register op2, Label *stackOverflow)
{
Register temp1 = op1;
Register temp2 = op2;
if (op1 == op2) {
// reuse glue as an op register for temporary
__ Pushq(glue);
temp2 = glue;
}
__ Movq(Operand(glue, JSThread::GlueData::GetStackLimitOffset(false)), temp1);
__ Movq(rsp, temp2);
__ Subq(temp1, temp2);
__ Movl(numArgs, temp1);
__ Shlq(3, temp1); // 3: each arg occupies 8 bytes
__ Cmpq(temp1, temp2);
if (op1 == op2) {
__ Popq(glue);
}
__ Jle(stackOverflow);
}
void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
Register op)
{
__ Movq(fp, rsp);
if (fp != rsp) {
__ Movq(fp, rsp);
}
__ Movq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException, op);
__ Movq(Operand(glue, op, Times8, JSThread::GlueData::GetRTStubEntriesOffset(false)), op);
if (glue != r13) {

View File

@ -81,5 +81,47 @@ void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register ar
__ Subq(1, argc);
__ Ja(&loopBeginning);
}
void CommonCall::PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
Register argv, Register op1, Register op2, Label *stackOverflow)
{
ASSERT(stackOverflow != nullptr);
StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
Register opArgc = argc;
Register op = op1;
if (op1 != op2) {
// use op2 as opArgc and will not change argc register
opArgc = op2;
__ Movq(argc, opArgc);
}
Label loopBeginning;
__ Bind(&loopBeginning);
__ Movq(Operand(argv, opArgc, Times8, -8), op); // 8: 8 bytes argv crash rdx=0x8
__ Pushq(op);
__ Subq(1, opArgc);
__ Ja(&loopBeginning);
}
void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
Register op2, Label *stackOverflow)
{
Register temp1 = op1;
Register temp2 = op2;
if (op1 == op2) {
// reuse glue as an op register for temporary
__ Pushq(glue);
temp2 = glue;
}
__ Movq(Operand(glue, JSThread::GlueData::GetStackLimitOffset(false)), temp1);
__ Movq(rsp, temp2);
__ Subq(temp1, temp2);
__ Movl(numArgs, temp1);
__ Shlq(3, temp1); // 3: each arg occupies 8 bytes
__ Cmpq(temp1, temp2);
if (op1 == op2) {
__ Popq(glue);
}
__ Jle(stackOverflow);
}
#undef __
} // namespace panda::ecmascript::x64

View File

@ -33,6 +33,10 @@ public:
static void PopAsmInterpBridgeFrame(ExtendedAssembler *assembler);
static void PushUndefinedWithArgc(ExtendedAssembler *assembler, Register argc);
static void GetArgvAtStack(ExtendedAssembler *assembler);
static void PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, Register argv,
Register op1, Register op2, Label *stackOverflow);
static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
Register op2, Label *stackOverflow);
};
class OptimizedCall : public CommonCall {
@ -57,7 +61,10 @@ public:
static void ConstructorJSCallWithArgV(ExtendedAssembler *assembler);
static void DeoptHandlerAsm(ExtendedAssembler *assembler);
private:
static void DeoptEnterAsmInterp(ExtendedAssembler *assembler);
static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall);
static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg);
@ -139,18 +146,12 @@ private:
Register contextRegister, Register pcRegister, Register operatorRegister);
static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler);
static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler);
static void CallBCStub(ExtendedAssembler *assembler, Register newSpRegister, Register glueRegister,
Register callTargetRegister, Register methodRegister, Register pcRegister);
static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
Register declaredNumArgsRegister);
static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
Register numVregsRegister);
static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
Register op1, Register op2, Label *stackOverflow);
static void PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, Register argv,
Register op1, Register op2, Label *stackOverflow);
static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs,
Register op1, Register op2, Label *stackOverflow);
static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
Register op);
static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister);
@ -158,7 +159,9 @@ private:
static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow);
static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister);
static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister,
Register callTargetRegister, Register methodRegister,
Register accRegister = rInvalid);
static void CallNativeEntry(ExtendedAssembler *assemblSer);
static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew);
static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode);

View File

@ -19,6 +19,7 @@
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/compiler/argument_accessor.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/ecma_runtime_call_info.h"
#include "ecmascript/frames.h"
#include "ecmascript/js_function.h"
@ -1221,5 +1222,104 @@ void OptimizedCall::ConstructorJSCallWithArgV(ExtendedAssembler *assembler)
PopOptimizedUnfoldArgVFrame(assembler);
__ Ret();
}
// Input: %rdi - glue
// %rsi - context
void OptimizedCall::DeoptEnterAsmInterp(ExtendedAssembler *assembler)
{
// rdi
Register glueRegister = __ GlueRegister();
Register context = rsi;
// rax, rdx, rcx, r8, r9, r10, r11 is free
Register tempRegister = rax;
Register opRegister = r10;
Register outputCount = rdx;
Register frameStateBase = rcx;
__ Movq(Operand(context, AsmStackContext::GetOutputCountOffset(false)), outputCount);
__ Leaq(Operand(context, AsmStackContext::GetSize(false)), frameStateBase);
Label stackOverflow;
// update fp
__ Movq(rsp, Operand(frameStateBase, AsmInterpretedFrame::GetFpOffset(false)));
PushArgsWithArgvAndCheckStack(assembler, glueRegister, outputCount,
frameStateBase, tempRegister, opRegister, &stackOverflow);
Register callTargetRegister = r8;
Register methodRegister = r9;
{
// r13, rbp, r12, rbx, r14, rsi, rdi
// glue sp pc constpool profile acc hotness
__ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetFunctionOffset(false)), callTargetRegister);
__ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetPcOffset(false)), r12);
__ Movq(Operand(frameStateBase, AsmInterpretedFrame::GetAccOffset(false)), rsi);
__ Movq(Operand(callTargetRegister, JSFunctionBase::METHOD_OFFSET), methodRegister);
__ Leaq(Operand(rsp, AsmInterpretedFrame::GetSize(false)), opRegister);
AsmInterpreterCall::DispatchCall(assembler, r12, opRegister, callTargetRegister, methodRegister, rsi);
}
__ Bind(&stackOverflow);
{
[[maybe_unused]] TempRegisterScope scope(assembler);
Register temp = __ TempRegister();
AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(assembler,
glueRegister, rsp, temp);
}
}
// Input: %rdi - glue
void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
{
__ BindAssemblerStub(RTSTUB_ID(DeoptHandlerAsm));
__ Pushq(rbp);
__ Movq(rsp, rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ PushCppCalleeSaveRegisters();
Register glueReg = rdi;
__ Push(glueReg);
__ Movq(rdi, rax); // glue
__ PushAlignBytes();
__ Pushq(0); // argc
__ Pushq(kungfu::RuntimeStubCSigns::ID_DeoptHandler);
__ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
__ Addq(3 * FRAME_SLOT_SIZE, rsp); // 3: skip runtimeId argc argv[0] argv[1]
__ Pop(glueReg);
Register context = rsi;
__ Movq(rax, context);
Label stackOverflow;
__ Cmpq(JSTaggedValue::VALUE_EXCEPTION, rax);
__ Je(&stackOverflow);
Label target;
__ PopCppCalleeSaveRegisters();
__ Movq(Operand(context, AsmStackContext::GetCallerFpOffset(false)), rbp);
__ Movq(Operand(context, AsmStackContext::GetCallFrameTopOffset(false)), rsp);
__ Subq(FRAME_SLOT_SIZE, rsp); // skip lr
PushAsmInterpBridgeFrame(assembler);
__ Callq(&target);
PopAsmInterpBridgeFrame(assembler);
__ Ret();
__ Bind(&target);
DeoptEnterAsmInterp(assembler);
__ Int3();
__ Bind(&stackOverflow);
{
__ Movq(rdi, rax);
__ Pushq(0); // argc
__ Pushq(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException);
__ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
__ Addq(16, rsp); // 16: skip runtimeId argc
__ PopCppCalleeSaveRegisters();
__ Addq(FRAME_SLOT_SIZE, rsp);
__ Popq(rbp);
__ Ret();
}
}
#undef __
} // namespace panda::ecmascript::x64

View File

@ -14,6 +14,7 @@
*/
#include "ecmascript/compiler/ts_type_lowering.h"
#include "ecmascript/llvm_stackmap_parser.h"
namespace panda::ecmascript::kungfu {
void TSTypeLowering::RunTSTypeLowering()
@ -28,11 +29,49 @@ void TSTypeLowering::RunTSTypeLowering()
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "================== ts type lowering print all gates Start==================";
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After ts type lowering "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGates(*bcBuilder_);
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
}
bool TSTypeLowering::IsTrustedType(GateRef gate) const
{
if (acc_.IsConstant(gate)) {
return true;
}
auto op = acc_.GetOpCode(gate);
if (acc_.IsTypedOperator(gate)) {
if (op == OpCode::TYPE_CONVERT) {
return true;
} else {
return !acc_.GetGateType(gate).IsIntType();
}
}
if (op == OpCode::JS_BYTECODE) {
auto pc = bcBuilder_->GetJSBytecode(gate);
EcmaOpcode bc = bcBuilder_->PcToOpcode(pc);
switch (bc) {
case EcmaOpcode::ADD2_IMM8_V8:
case EcmaOpcode::SUB2_IMM8_V8:
case EcmaOpcode::MUL2_IMM8_V8:
case EcmaOpcode::INC_IMM8:
return !acc_.GetGateType(gate).IsIntType();
case EcmaOpcode::LESSEQ_IMM8_V8:
return true;
default:
break;
}
}
return false;
}
void TSTypeLowering::Lower(GateRef gate)
{
auto pc = bcBuilder_->GetJSBytecode(gate);
@ -53,7 +92,6 @@ void TSTypeLowering::Lower(GateRef gate)
LowerTypedDiv(gate);
break;
case EcmaOpcode::MOD2_IMM8_V8:
LowerTypedMod(gate);
break;
case EcmaOpcode::LESS_IMM8_V8:
LowerTypedLess(gate);
@ -95,7 +133,7 @@ void TSTypeLowering::Lower(GateRef gate)
// lower JS_EXP
break;
case EcmaOpcode::TONUMERIC_IMM8:
// lower ToNumberic
LowerTypeToNumeric(gate);
break;
case EcmaOpcode::NEG_IMM8:
// lower JS_NEG
@ -104,85 +142,105 @@ void TSTypeLowering::Lower(GateRef gate)
// lower JS_NOT
break;
case EcmaOpcode::INC_IMM8:
// lower JS_INC
LowerTypedInc(gate);
break;
case EcmaOpcode::DEC_IMM8:
// lower JS_DEC
LowerTypedDec(gate);
break;
case EcmaOpcode::JEQZ_IMM8:
case EcmaOpcode::JEQZ_IMM16:
case EcmaOpcode::JEQZ_IMM32:
LowerConditionJump(gate);
break;
default:
break;
}
}
void TSTypeLowering::RebuildSlowpathCfg(GateRef hir, std::map<GateRef, size_t> &stateGateMap)
void TSTypeLowering::DeleteGates(GateRef hir, std::vector<GateRef> &unusedGate)
{
acc_.ReplaceStateIn(hir, builder_.GetState());
acc_.ReplaceDependIn(hir, builder_.GetDepend());
auto uses = acc_.Uses(hir);
GateRef stateGate = Circuit::NullGate();
for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
const OpCode op = acc_.GetOpCode(*useIt);
if (op == OpCode::IF_SUCCESS) {
stateGate = *useIt;
builder_.SetState(*useIt);
break;
for (auto &gate : unusedGate) {
auto uses = acc_.Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) {
if (acc_.GetOpCode(gate) == OpCode::IF_EXCEPTION && acc_.GetOpCode(*useIt) == OpCode::MERGE) {
// handle exception merge has only one input, using state entry and depend entry to replace merge and
// dependselector.
if (acc_.GetNumIns(*useIt) == 1) {
GateRef stateEntry = Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY));
GateRef dependEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY));
auto mergeUses = acc_.Uses(*useIt);
for (auto mergeUseIt = mergeUses.begin(); mergeUseIt != uses.end(); ++mergeUseIt) {
if (acc_.GetOpCode(*mergeUseIt) == OpCode::DEPEND_SELECTOR) {
auto dependSelectorUses = acc_.Uses(*mergeUseIt);
acc_.ReplaceIn(*dependSelectorUses.begin(), 0, dependEntry);
acc_.DeleteGate(*mergeUseIt);
break;
}
}
acc_.ReplaceIn(*useIt, 0, stateEntry);
} else {
acc_.DecreaseIn(useIt);
}
}
}
acc_.DeleteGate(gate);
}
auto nextUses = acc_.Uses(stateGate);
for (auto it = nextUses.begin(); it != nextUses.end(); ++it) {
if (it.GetOpCode().IsState()) {
stateGateMap[*it] = it.GetIndex();
}
}
builder_.SetDepend(hir);
acc_.DeleteGate(hir);
}
void TSTypeLowering::GenerateSuccessMerge(std::vector<GateRef> &successControl)
{
GateRef stateMerge = builder_.GetState();
GateRef dependSelect = builder_.GetDepend();
successControl.emplace_back(stateMerge);
successControl.emplace_back(dependSelect);
}
void TSTypeLowering::ReplaceHirToFastPathCfg(GateRef hir, GateRef outir, const std::vector<GateRef> &successControl)
void TSTypeLowering::ReplaceHIRGate(GateRef hir, GateRef outir, GateRef state, GateRef depend,
std::vector<GateRef> &unusedGate)
{
std::map<GateRef, size_t> deleteMap;
auto uses = acc_.Uses(hir);
for (auto useIt = uses.begin(); useIt != uses.end();) {
const OpCode op = acc_.GetOpCode(*useIt);
if (op == OpCode::JS_BYTECODE && useIt.GetIndex() == 1) {
acc_.ReplaceStateIn(*useIt, successControl[0]);
useIt = acc_.ReplaceIn(useIt, successControl[1]);
if (op == OpCode::IF_SUCCESS) {
// success path use fastpath state
unusedGate.emplace_back(*useIt);
auto successUse = acc_.Uses(*useIt).begin();
acc_.ReplaceIn(successUse, state);
++useIt;
} else if (op == OpCode::IF_EXCEPTION) {
// exception path needs to delete all related nodes
unusedGate.emplace_back(*useIt);
auto exceptionUse = acc_.Uses(*useIt);
auto exceptionUseIt = exceptionUse.begin();
if (acc_.GetOpCode(*exceptionUseIt) == OpCode::MERGE) {
auto mergeUse = acc_.Uses(*exceptionUseIt);
// handle exception->merge->value_selector/depend_selector
for (auto mergeUseIt = mergeUse.begin(); mergeUseIt != mergeUse.end();) {
if (acc_.GetOpCode(*mergeUseIt) == OpCode::VALUE_SELECTOR ||
acc_.GetOpCode(*mergeUseIt) == OpCode::DEPEND_SELECTOR) {
deleteMap[*mergeUseIt] = exceptionUseIt.GetIndex() + 1;
}
++mergeUseIt;
}
}
++useIt;
} else if (op == OpCode::RETURN) {
// replace return valueIn and dependIn
if (acc_.IsValueIn(useIt)) {
useIt = acc_.ReplaceIn(useIt, outir);
continue;
}
if (acc_.GetOpCode(acc_.GetIn(*useIt, 0)) != OpCode::IF_EXCEPTION) {
acc_.ReplaceStateIn(*useIt, successControl[0]);
acc_.ReplaceDependIn(*useIt, successControl[1]);
acc_.ReplaceValueIn(*useIt, outir);
}
++useIt;
} else if (op == OpCode::IF_SUCCESS || op == OpCode::IF_EXCEPTION) {
++useIt;
} else if (op == OpCode::VALUE_SELECTOR) {
if (*useIt != outir) {
useIt = acc_.ReplaceIn(useIt, outir);
} else if (acc_.IsDependIn(useIt)) {
useIt = acc_.ReplaceIn(useIt, depend);
} else {
++useIt;
}
} else if (op == OpCode::DEPEND_SELECTOR) {
if (*useIt != successControl[1]) {
useIt = acc_.ReplaceIn(useIt, successControl[1]);
} else {
if (acc_.GetOpCode(acc_.GetIn(acc_.GetIn(*useIt, 0), useIt.GetIndex() - 1)) == OpCode::IF_EXCEPTION) {
++useIt;
} else {
useIt = acc_.ReplaceIn(useIt, depend);
}
} else {
useIt = acc_.ReplaceIn(useIt, outir);
}
}
for (auto it = deleteMap.begin(); it != deleteMap.end(); it++) {
acc_.DecreaseIn(it->first, it->second);
}
}
void TSTypeLowering::LowerTypedAdd(GateRef gate)
@ -192,8 +250,9 @@ void TSTypeLowering::LowerTypedAdd(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_ADD>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -204,8 +263,9 @@ void TSTypeLowering::LowerTypedSub(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_SUB>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -216,8 +276,9 @@ void TSTypeLowering::LowerTypedMul(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_MUL>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -228,8 +289,9 @@ void TSTypeLowering::LowerTypedMod(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCalculate<TypedBinOp::TYPED_MOD>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_MOD>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -240,8 +302,9 @@ void TSTypeLowering::LowerTypedLess(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_LESS>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_LESS>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -252,8 +315,9 @@ void TSTypeLowering::LowerTypedLessEq(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_LESSEQ>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -264,8 +328,9 @@ void TSTypeLowering::LowerTypedGreater(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_GREATER>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -276,8 +341,9 @@ void TSTypeLowering::LowerTypedGreaterEq(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_GREATEREQ>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -288,8 +354,9 @@ void TSTypeLowering::LowerTypedDiv(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCalculate<TypedBinOp::TYPED_DIV>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_DIV>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -300,8 +367,9 @@ void TSTypeLowering::LowerTypedEq(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_EQ>(gate);
return;
SpeculateNumbers<TypedBinOp::TYPED_EQ>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -312,77 +380,95 @@ void TSTypeLowering::LowerTypedNotEq(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
if (leftType.IsNumberType() && rightType.IsNumberType()) {
SpeculateNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
SpeculateNumbers<TypedBinOp::TYPED_NOTEQ>(gate);
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
void TSTypeLowering::LowerTypedInc(GateRef gate)
{
GateRef value = acc_.GetValueIn(gate, 0);
GateType valueType = acc_.GetGateType(value);
if (valueType.IsNumberType()) {
SpeculateNumber<TypedUnOp::TYPED_INC>(gate);
return;
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
void TSTypeLowering::LowerTypedDec(GateRef gate)
{
GateRef value = acc_.GetValueIn(gate, 0);
GateType valueType = acc_.GetGateType(value);
if (valueType.IsNumberType()) {
SpeculateNumber<TypedUnOp::TYPED_DEC>(gate);
return;
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
template<TypedBinOp Op>
void TSTypeLowering::SpeculateNumberCalculate(GateRef gate)
void TSTypeLowering::SpeculateNumbers(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
Label isNumber(&builder_);
Label notNumber(&builder_);
Label exit(&builder_);
GateType numberType = GateType::NumberType();
DEFVAlUE(result, (&builder_), VariableType(MachineType::I64, numberType), builder_.HoleConstant());
builder_.Branch(builder_.BoolAnd(builder_.TypeCheck(numberType, left), builder_.TypeCheck(numberType, right)),
&isNumber, &notNumber);
std::map<GateRef, size_t> stateGateMap;
builder_.Bind(&isNumber);
{
result = builder_.NumberBinaryOp<Op>(left, right);
builder_.Jump(&exit);
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
GateType gateType = acc_.GetGateType(gate);
GateRef check = Circuit::NullGate();
if (IsTrustedType(left) && IsTrustedType(right)) {
acc_.DeleteGuardAndFrameState(gate);
} else if (IsTrustedType(left)) {
check = builder_.TypeCheck(rightType, right);
} else if (IsTrustedType(right)) {
check = builder_.TypeCheck(leftType, left);
} else {
check = builder_.BoolAnd(builder_.TypeCheck(leftType, left), builder_.TypeCheck(rightType, right));
}
builder_.Bind(&notNumber);
{
// slowpath
result = gate;
RebuildSlowpathCfg(gate, stateGateMap);
builder_.Jump(&exit);
// guard maybe not a GUARD
GateRef guard = acc_.GetDep(gate);
if (check != Circuit::NullGate()) {
acc_.ReplaceIn(guard, 1, check);
}
builder_.Bind(&exit);
for (auto [state, index] : stateGateMap) {
acc_.ReplaceIn(state, index, builder_.GetState());
}
std::vector<GateRef> successControl;
GenerateSuccessMerge(successControl);
ReplaceHirToFastPathCfg(gate, *result, successControl);
// Replace the old NumberBinaryOp<Op> with TypedBinaryOp<Op>
GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType);
acc_.SetDep(result, guard);
std::vector<GateRef> removedGate;
ReplaceHIRGate(gate, result, builder_.GetState(), builder_.GetDepend(), removedGate);
DeleteGates(gate, removedGate);
}
template<TypedBinOp Op>
void TSTypeLowering::SpeculateNumberCompare(GateRef gate)
template<TypedUnOp Op>
void TSTypeLowering::SpeculateNumber(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
Label isNumber(&builder_);
Label notNumber(&builder_);
Label exit(&builder_);
GateType numberType = GateType::NumberType();
DEFVAlUE(result, (&builder_), VariableType(MachineType::I64, GateType::BooleanType()), builder_.HoleConstant());
builder_.Branch(builder_.BoolAnd(builder_.TypeCheck(numberType, left), builder_.TypeCheck(numberType, right)),
&isNumber, &notNumber);
std::map<GateRef, size_t> stateGateMap;
builder_.Bind(&isNumber);
{
result = builder_.NumberBinaryOp<Op>(left, right);
builder_.Jump(&exit);
GateRef value = acc_.GetValueIn(gate, 0);
GateType valueType = acc_.GetGateType(value);
GateType gateType = acc_.GetGateType(gate);
GateRef check = Circuit::NullGate();
if (IsTrustedType(value)) {
acc_.DeleteGuardAndFrameState(gate);
} else {
check = builder_.TypeCheck(valueType, value);
}
builder_.Bind(&notNumber);
{
// slowpath
result = gate;
RebuildSlowpathCfg(gate, stateGateMap);
builder_.Jump(&exit);
// guard maybe not a GUARD
GateRef guard = acc_.GetDep(gate);
if (check != Circuit::NullGate()) {
acc_.ReplaceIn(guard, 1, check);
}
builder_.Bind(&exit);
for (auto [state, index] : stateGateMap) {
acc_.ReplaceIn(state, index, builder_.GetState());
}
std::vector<GateRef> successControl;
GenerateSuccessMerge(successControl);
ReplaceHirToFastPathCfg(gate, *result, successControl);
GateRef result = builder_.TypedUnaryOp<Op>(value, valueType, gateType);
acc_.SetDep(result, guard);
std::vector<GateRef> removedGate;
ReplaceHIRGate(gate, result, builder_.GetState(), builder_.GetDepend(), removedGate);
DeleteGates(gate, removedGate);
}
void TSTypeLowering::LowerTypeToNumeric(GateRef gate)
@ -391,38 +477,66 @@ void TSTypeLowering::LowerTypeToNumeric(GateRef gate)
GateType srcType = acc_.GetGateType(src);
if (srcType.IsPrimitiveType() && !srcType.IsStringType()) {
LowerPrimitiveTypeToNumber(gate);
return;
} else {
acc_.DeleteGuardAndFrameState(gate);
}
}
void TSTypeLowering::LowerPrimitiveTypeToNumber(GateRef gate)
{
Label isPrimitive(&builder_);
Label notPrimitive(&builder_);
Label exit(&builder_);
GateRef src = acc_.GetValueIn(gate, 0);
GateType srcType = acc_.GetGateType(src);
DEFVAlUE(result, (&builder_), VariableType(MachineType::I64, GateType::NumberType()), builder_.HoleConstant());
builder_.Branch(builder_.TypeCheck(srcType, src), &isPrimitive, &notPrimitive);
std::map<GateRef, size_t> stateGateMap;
builder_.Bind(&isPrimitive);
{
result = builder_.PrimitiveToNumber(src, VariableType(MachineType::I64, srcType));
builder_.Jump(&exit);
GateRef check = Circuit::NullGate();
if (IsTrustedType(src)) {
acc_.DeleteGuardAndFrameState(gate);
} else {
check = builder_.TypeCheck(srcType, src);
}
builder_.Bind(&notPrimitive);
{
// slowpath
result = gate;
RebuildSlowpathCfg(gate, stateGateMap);
builder_.Jump(&exit);
// guard maybe not a GUARD
GateRef guard = acc_.GetDep(gate);
if (check != Circuit::NullGate()) {
acc_.ReplaceIn(guard, 1, check);
}
builder_.Bind(&exit);
for (auto [state, index] : stateGateMap) {
acc_.ReplaceIn(state, index, builder_.GetState());
}
std::vector<GateRef> successControl;
GenerateSuccessMerge(successControl);
ReplaceHirToFastPathCfg(gate, *result, successControl);
GateRef result = builder_.PrimitiveToNumber(src, VariableType(MachineType::I64, srcType));
acc_.SetDep(result, guard);
std::vector<GateRef> removedGate;
ReplaceHIRGate(gate, result, builder_.GetState(), builder_.GetDepend(), removedGate);
DeleteGates(gate, removedGate);
}
} // namespace panda::ecmascript
void TSTypeLowering::LowerConditionJump(GateRef gate)
{
GateRef condition = acc_.GetValueIn(gate, 0);
GateType conditionType = acc_.GetGateType(condition);
if (conditionType.IsBooleanType() && IsTrustedType(condition)) {
SpeculateConditionJump(gate);
}
}
void TSTypeLowering::SpeculateConditionJump(GateRef gate)
{
GateRef value = acc_.GetValueIn(gate, 0);
GateRef condition = builder_.IsSpecial(value, JSTaggedValue::VALUE_FALSE);
GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition);
ReplaceGate(gate, ifBranch, builder_.GetDepend(), Circuit::NullGate());
}
void TSTypeLowering::ReplaceGate(GateRef gate, GateRef state, GateRef depend, GateRef value)
{
auto uses = acc_.Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end();) {
if (acc_.IsStateIn(useIt)) {
useIt = acc_.ReplaceIn(useIt, state);
} else if (acc_.IsDependIn(useIt)) {
useIt = acc_.ReplaceIn(useIt, depend);
} else if (acc_.IsValueIn(useIt)) {
useIt = acc_.ReplaceIn(useIt, value);
} else {
UNREACHABLE();
}
}
acc_.DeleteGate(gate);
}
} // namespace panda::ecmascript

View File

@ -24,10 +24,11 @@ namespace panda::ecmascript::kungfu {
class TSTypeLowering {
public:
TSTypeLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, CompilationConfig *cmpCfg,
TSManager *tsManager, bool enableLog)
TSManager *tsManager, bool enableLog, const std::string& name)
: bcBuilder_(bcBuilder), circuit_(circuit), acc_(circuit), builder_(circuit, cmpCfg),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))), tsManager_(tsManager),
enableLog_(enableLog) {}
enableLog_(enableLog), methodName_(name) {}
~TSTypeLowering() = default;
void RunTSTypeLowering();
@ -37,10 +38,17 @@ private:
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
void Lower(GateRef gate);
void RebuildSlowpathCfg(GateRef hir, std::map<GateRef, size_t> &stateGateMap);
void GenerateSuccessMerge(std::vector<GateRef> &successControl);
void ReplaceHirToFastPathCfg(GateRef hir, GateRef outir, const std::vector<GateRef> &successControl);
void DeleteGates(GateRef hir, std::vector<GateRef> &unusedGate);
void ReplaceHIRGate(GateRef hir, GateRef outir, GateRef state, GateRef depend,
std::vector<GateRef> &unuseGate);
void ReplaceGate(GateRef gate, GateRef state, GateRef depend, GateRef value);
void LowerTypedAdd(GateRef gate);
void LowerTypedSub(GateRef gate);
void LowerTypedMul(GateRef gate);
@ -52,13 +60,20 @@ private:
void LowerTypedDiv(GateRef gate);
void LowerTypedEq(GateRef gate);
void LowerTypedNotEq(GateRef gate);
void LowerTypedInc(GateRef gate);
void LowerTypedDec(GateRef gate);
void LowerTypeToNumeric(GateRef gate);
void LowerPrimitiveTypeToNumber(GateRef gate);
void LowerConditionJump(GateRef gate);
// TypeTrusted means the type of gate is already typecheck-passed, or the gate is constant and no need to check.
bool IsTrustedType(GateRef gate) const;
template<TypedBinOp Op>
void SpeculateNumberCalculate(GateRef gate);
template<TypedBinOp Op>
void SpeculateNumberCompare(GateRef gate);
void SpeculateNumbers(GateRef gate);
template<TypedUnOp Op>
void SpeculateNumber(GateRef gate);
void SpeculateConditionJump(GateRef gate);
BytecodeCircuitBuilder *bcBuilder_ {nullptr};
Circuit *circuit_ {nullptr};
GateAccessor acc_;
@ -66,6 +81,7 @@ private:
GateRef dependEntry_ {Gate::InvalidGateRef};
[[maybe_unused]]TSManager *tsManager_ {nullptr};
bool enableLog_ {false};
std::string methodName_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_TS_TYPE_LOWERING_H

View File

@ -20,7 +20,7 @@ Type::Type(GateType payload) : payload(payload) {}
bool Type::IsBitset() const
{
return (this->payload.GetType() & 1U) == 1;
return (this->payload.Value() & 1U) == 1;
}
Type::~Type() {}

View File

@ -32,7 +32,7 @@ public:
~GateType() = default;
uint32_t GetType() const
uint32_t Value() const
{
return type_;
}
@ -74,6 +74,12 @@ public:
return GateType(r);
}
static GateType DoubleType()
{
GlobalTSTypeRef r(0, static_cast<int>(TSPrimitiveType::DOUBLE));
return GateType(r);
}
static GateType BooleanType()
{
GlobalTSTypeRef r(0, static_cast<int>(TSPrimitiveType::BOOLEAN));
@ -127,7 +133,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::ANY));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::ANY));
}
bool IsNumberType() const
@ -135,7 +141,25 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::NUMBER));
return (m == 0) && ((l == static_cast<uint32_t>(TSPrimitiveType::NUMBER)) ||
(l == static_cast<uint32_t>(TSPrimitiveType::INT)) ||
(l == static_cast<uint32_t>(TSPrimitiveType::DOUBLE)));
}
bool IsIntType() const
{
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::INT));
}
bool IsDoubleType() const
{
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::DOUBLE));
}
bool IsStringType() const
@ -143,7 +167,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::STRING));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::STRING));
}
bool IsNullType() const
@ -151,7 +175,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::NULL_TYPE));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::NULL_TYPE));
}
bool IsUndefinedType() const
@ -159,7 +183,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::UNDEFINED));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::UNDEFINED));
}
bool IsBooleanType() const
@ -167,7 +191,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::BOOLEAN));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::BOOLEAN));
}
bool IsBigIntType() const
@ -175,7 +199,7 @@ public:
GlobalTSTypeRef r = GetGTRef();
uint32_t m = r.GetModuleId();
uint32_t l = r.GetLocalId();
return IsTSType() && (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::BIG_INT));
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::BIG_INT));
}
bool IsPrimitiveType() const
@ -219,16 +243,6 @@ public:
return type_ >= other.type_;
}
bool IsTSType() const
{
return (type_ & MIR_TYPE_MASK) == 0;
}
bool IsIRType() const
{
return (type_ & MIR_TYPE_MASK) != 0;
}
GlobalTSTypeRef GetGTRef() const
{
uint32_t r = type_ & (~MIR_TYPE_MASK);

View File

@ -60,7 +60,7 @@ void TypeInfer::TraverseCircuit()
bool TypeInfer::UpdateType(GateRef gate, const GateType type)
{
auto preType = gateAccessor_.GetGateType(gate);
if (type.IsTSType() && !type.IsAnyType() && type != preType) {
if (type != preType) {
gateAccessor_.SetGateType(gate, type);
return true;
}
@ -105,9 +105,6 @@ bool TypeInfer::Infer(GateRef gate)
switch (op) {
case EcmaOpcode::LDNAN:
case EcmaOpcode::LDINFINITY:
case EcmaOpcode::SUB2_IMM8_V8:
case EcmaOpcode::MUL2_IMM8_V8:
case EcmaOpcode::DIV2_IMM8_V8:
case EcmaOpcode::MOD2_IMM8_V8:
case EcmaOpcode::SHL2_IMM8_V8:
case EcmaOpcode::ASHR2_IMM8_V8:
@ -119,8 +116,6 @@ bool TypeInfer::Infer(GateRef gate)
case EcmaOpcode::TONUMERIC_IMM8:
case EcmaOpcode::NEG_IMM8:
case EcmaOpcode::NOT_IMM8:
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::DEC_IMM8:
case EcmaOpcode::EXP_IMM8_V8:
case EcmaOpcode::STARRAYSPREAD_V8_V8:
case EcmaOpcode::DEPRECATED_TONUMBER_PREF_V8:
@ -169,6 +164,15 @@ bool TypeInfer::Infer(GateRef gate)
return InferTypeOf(gate);
case EcmaOpcode::ADD2_IMM8_V8:
return InferAdd2(gate);
case EcmaOpcode::SUB2_IMM8_V8:
return InferSub2(gate);
case EcmaOpcode::MUL2_IMM8_V8:
return InferMul2(gate);
case EcmaOpcode::DIV2_IMM8_V8:
return InferDiv2(gate);
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::DEC_IMM8:
return InferIncDec(gate);
case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
@ -276,7 +280,7 @@ bool TypeInfer::InferPhiGate(GateRef gate)
if (valueInType.IsAnyType()) {
return UpdateType(gate, valueInType);
}
typeList.emplace_back(GlobalTSTypeRef(valueInType.GetType()));
typeList.emplace_back(valueInType.GetGTRef());
}
// deduplicate
auto deduplicateIndex = std::unique(typeList.begin(), typeList.end());
@ -321,14 +325,14 @@ bool TypeInfer::InferLdNull(GateRef gate)
bool TypeInfer::InferLdai(GateRef gate)
{
auto numberType = GateType::NumberType();
return UpdateType(gate, numberType);
auto intType = GateType::IntType();
return UpdateType(gate, intType);
}
bool TypeInfer::InferFLdai(GateRef gate)
{
auto numberType = GateType::NumberType();
return UpdateType(gate, numberType);
auto doubleType = GateType::DoubleType();
return UpdateType(gate, doubleType);
}
bool TypeInfer::InferLdSymbol(GateRef gate)
@ -351,6 +355,16 @@ bool TypeInfer::InferTypeOf(GateRef gate)
return UpdateType(gate, gateType);
}
/*
* Type Infer rule(satisfy commutative law):
* number + number = number
* int + number = number
* double + number = number
* int + int = int
* int + double = double
* double + double = double
* string + string = string
*/
bool TypeInfer::InferAdd2(GateRef gate)
{
// 2: number of value inputs
@ -360,12 +374,118 @@ bool TypeInfer::InferAdd2(GateRef gate)
if (firInType.IsStringType() || secInType.IsStringType()) {
return UpdateType(gate, GateType::StringType());
}
if ((firInType.IsIntType() && secInType.IsDoubleType()) ||
(firInType.IsDoubleType() && secInType.IsIntType()) ||
(firInType.IsDoubleType() && secInType.IsDoubleType())) {
return UpdateType(gate, GateType::DoubleType());
}
if ((firInType.IsIntType() && secInType.IsIntType())) {
return UpdateType(gate, GateType::IntType());
}
if (firInType.IsNumberType() && secInType.IsNumberType()) {
return UpdateType(gate, GateType::NumberType());
}
return UpdateType(gate, GateType::AnyType());
}
/*
* Type Infer rule(satisfy commutative law):
* number - number = number
* int - number = number
* double - number = number
* int - int = int
* int - double = double
* double - double = double
*/
bool TypeInfer::InferSub2(GateRef gate)
{
// 2: number of value inputs
ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
if ((firInType.IsIntType() && secInType.IsDoubleType()) ||
(firInType.IsDoubleType() && secInType.IsIntType()) ||
(firInType.IsDoubleType() && secInType.IsDoubleType())) {
return UpdateType(gate, GateType::DoubleType());
}
if ((firInType.IsIntType() && secInType.IsIntType())) {
return UpdateType(gate, GateType::IntType());
}
return UpdateType(gate, GateType::NumberType());
}
/*
* Type Infer rule(satisfy commutative law):
* number * number = number
* int * number = number
* double * number = number
* int * int = int
* int * double = double
* double * double = double
*/
bool TypeInfer::InferMul2(GateRef gate)
{
// 2: number of value inputs
ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
if ((firInType.IsIntType() && secInType.IsDoubleType()) ||
(firInType.IsDoubleType() && secInType.IsIntType()) ||
(firInType.IsDoubleType() && secInType.IsDoubleType())) {
return UpdateType(gate, GateType::DoubleType());
}
if ((firInType.IsIntType() && secInType.IsIntType())) {
return UpdateType(gate, GateType::IntType());
}
return UpdateType(gate, GateType::NumberType());
}
/*
* Type Infer rule(satisfy commutative law):
* number / number = number
* int / number = number
* double / number = number
* int / int = double
* int / double = double
* double / double = double
*/
bool TypeInfer::InferDiv2(GateRef gate)
{
// 2: number of value inputs
ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
if ((firInType.IsIntType() && secInType.IsIntType()) ||
(firInType.IsIntType() && secInType.IsDoubleType()) ||
(firInType.IsDoubleType() && secInType.IsIntType()) ||
(firInType.IsDoubleType() && secInType.IsDoubleType())) {
return UpdateType(gate, GateType::DoubleType());
}
return UpdateType(gate, GateType::NumberType());
}
/*
* Type Infer rule:
* number++ = number
* number-- = number
* int++ = int
* int-- = int
* double++ = double
* double-- = double
*/
bool TypeInfer::InferIncDec(GateRef gate)
{
ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
if (firInType.IsDoubleType()) {
return UpdateType(gate, GateType::DoubleType());
}
if (firInType.IsIntType()) {
return UpdateType(gate, GateType::IntType());
}
return UpdateType(gate, GateType::NumberType());
}
bool TypeInfer::InferLdObjByIndex(GateRef gate)
{
// 2: number of value inputs
@ -424,7 +544,7 @@ bool TypeInfer::InferLdObjByName(GateRef gate)
// 2: number of value inputs
ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
if (objType.IsTSType()) {
if (!objType.IsAnyType()) {
if (tsManager_->IsArrayTypeKind(objType)) {
auto builtinGt = GlobalTSTypeRef(TSModuleTable::BUILTINS_TABLE_ID, TSManager::BUILTIN_ARRAY_ID);
auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
@ -470,7 +590,7 @@ bool TypeInfer::InferCallFunction(GateRef gate, bool isDeprecated)
funcIndex = gateAccessor_.GetNumValueIn(gate) - 2;
}
auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
if (funcType.IsTSType() && tsManager_->IsFunctionTypeKind(funcType)) {
if (tsManager_->IsFunctionTypeKind(funcType)) {
auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
return UpdateType(gate, returnType);
}
@ -480,20 +600,18 @@ bool TypeInfer::InferCallFunction(GateRef gate, bool isDeprecated)
bool TypeInfer::InferLdObjByValue(GateRef gate)
{
auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
if (objType.IsTSType()) {
// handle array
if (tsManager_->IsArrayTypeKind(objType)) {
auto elementType = tsManager_->GetArrayParameterTypeGT(objType);
return UpdateType(gate, elementType);
}
// handle object
if (IsObjectOrClass(objType)) {
auto valueGate = gateAccessor_.GetValueIn(gate, 1);
if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
auto value = gateAccessor_.GetBitField(valueGate);
auto type = GetPropType(objType, value);
return UpdateType(gate, type);
}
// handle array
if (tsManager_->IsArrayTypeKind(objType)) {
auto elementType = tsManager_->GetArrayParameterTypeGT(objType);
return UpdateType(gate, elementType);
}
// handle object
if (IsObjectOrClass(objType)) {
auto valueGate = gateAccessor_.GetValueIn(gate, 1);
if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
auto value = gateAccessor_.GetBitField(valueGate);
auto type = GetPropType(objType, value);
return UpdateType(gate, type);
}
}
return false;
@ -581,17 +699,13 @@ void TypeInfer::PrintAllByteCodesTypes() const
if (findIt != bytecodeToGate.end()) {
GateRef gate = bytecodeToGate.at(pc);
GateType type = gateAccessor_.GetGateType(gate);
if (type.IsTSType()) {
if (!tsManager_->IsPrimitiveTypeKind(type)) {
GlobalTSTypeRef gt = GlobalTSTypeRef(type.GetType());
LOG_COMPILER(INFO) << " " << inst << ", type: " + tsManager_->GetTypeStr(type)
<< ", [moduleId: " + std::to_string(gt.GetModuleId())
<< "], [localId: " + std::to_string(gt.GetLocalId()) + "]";
} else {
LOG_COMPILER(INFO) << " " << inst << ", type: " + tsManager_->GetTypeStr(type);
}
if (!tsManager_->IsPrimitiveTypeKind(type)) {
GlobalTSTypeRef gt = type.GetGTRef();
LOG_COMPILER(INFO) << " " << inst << ", type: " + tsManager_->GetTypeStr(type)
<< ", [moduleId: " + std::to_string(gt.GetModuleId())
<< ", [localId: " + std::to_string(gt.GetLocalId()) + "]";
} else {
LOG_COMPILER(INFO) << " " << inst;
LOG_COMPILER(INFO) << " " << inst << ", type: " + tsManager_->GetTypeStr(type);
}
}
}
@ -691,13 +805,11 @@ std::string TypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *
// handle ByteCode gate: print gate id, bytecode and line number in source code.
log += "bytecode: " + builder_->GetBytecodeStr(gate) + ", ";
GateType type = gateAccessor_.GetGateType(gate);
if (type.IsTSType()) {
log += "type: " + tsManager_->GetTypeStr(type) + ", ";
if (!tsManager_->IsPrimitiveTypeKind(type)) {
GlobalTSTypeRef gt = GlobalTSTypeRef(type.GetType());
log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", ";
log += "localId: " + std::to_string(gt.GetLocalId()) + "], ";
}
log += "type: " + tsManager_->GetTypeStr(type) + ", ";
if (!tsManager_->IsPrimitiveTypeKind(type)) {
GlobalTSTypeRef gt = type.GetGTRef();
log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", ";
log += "localId: " + std::to_string(gt.GetLocalId()) + "], ";
}
int32_t lineNumber = 0;

View File

@ -25,13 +25,21 @@
namespace panda::ecmascript::kungfu {
class TypeInfer {
public:
TypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, const JSHandle<JSTaggedValue> &constantPool,
TSManager *tsManager, LexEnvManager *lexEnvManager, size_t methodId, bool enableLog)
TypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit,
const JSHandle<JSTaggedValue> &constantPool, TSManager *tsManager,
LexEnvManager *lexEnvManager, size_t methodId, bool enableLog,
const std::string& name)
: builder_(builder), circuit_(circuit), constantPool_(constantPool), gateAccessor_(circuit),
tsManager_(tsManager), lexEnvManager_(lexEnvManager), methodId_(methodId), enableLog_(enableLog) {}
tsManager_(tsManager), lexEnvManager_(lexEnvManager), methodId_(methodId), enableLog_(enableLog),
methodName_(name)
{
}
~TypeInfer() = default;
NO_COPY_SEMANTIC(TypeInfer);
NO_MOVE_SEMANTIC(TypeInfer);
void TraverseCircuit();
bool IsLogEnabled() const
@ -39,6 +47,11 @@ public:
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
private:
bool UpdateType(GateRef gate, const GateType type);
bool UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef);
@ -56,6 +69,10 @@ private:
bool InferThrow(GateRef gate);
bool InferTypeOf(GateRef gate);
bool InferAdd2(GateRef gate);
bool InferSub2(GateRef gate);
bool InferMul2(GateRef gate);
bool InferDiv2(GateRef gate);
bool InferIncDec(GateRef gate);
bool InferLdObjByIndex(GateRef gate);
bool InferLdGlobalVar(GateRef gate);
bool InferReturnUndefined(GateRef gate);
@ -91,10 +108,6 @@ private:
return flag;
}
// tools used for debug type problems, will be enabled by each option:
// --compiler-log && --mlist-for-log
// --assert-types
// --print-any-types
void PrintAllByteCodesTypes() const;
void Verify() const;
void TypeCheck(GateRef gate) const;
@ -111,6 +124,7 @@ private:
LexEnvManager *lexEnvManager_ {nullptr};
size_t methodId_ {0};
bool enableLog_ {false};
std::string methodName_;
std::map<uint16_t, GateType> stringIdToGateType_;
};
} // namespace panda::ecmascript::kungfu

File diff suppressed because it is too large Load Diff

View File

@ -98,10 +98,11 @@ namespace panda::ecmascript::kungfu {
class TypeLowering {
public:
TypeLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, CompilationConfig *cmpCfg, TSManager *tsManager,
bool enableLog)
bool enableLog, const std::string& name)
: bcBuilder_(bcBuilder), circuit_(circuit), acc_(circuit), builder_(circuit, cmpCfg),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))), tsManager_(tsManager),
enableLog_(enableLog) {}
enableLog_(enableLog), methodName_(name) {}
~TypeLowering() = default;
void RunTypeLowering();
@ -112,6 +113,11 @@ private:
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
void Lower(GateRef gate);
void LowerType(GateRef gate);
void LowerTypeCheck(GateRef gate);
@ -129,7 +135,11 @@ private:
void LowerTypedDiv(GateRef gate);
void LowerTypedEq(GateRef gate);
void LowerTypedNotEq(GateRef gate);
void LowerTypedInc(GateRef gate);
void LowerTypedDec(GateRef gate);
void LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType);
void LowerIntCheck(GateRef gate);
void LowerDoubleCheck(GateRef gate);
void LowerNumberCheck(GateRef gate);
void LowerNumberAdd(GateRef gate);
void LowerNumberSub(GateRef gate);
@ -142,29 +152,26 @@ private:
void LowerNumberDiv(GateRef gate);
void LowerNumberEq(GateRef gate);
void LowerNumberNotEq(GateRef gate);
void GenerateSuccessMerge(std::vector<GateRef> &successControl);
void RebuildSlowpathCfg(GateRef hir, std::map<GateRef, size_t> &stateGateMap);
void ReplaceHirToCall(GateRef hirGate, GateRef callGate, bool noThrow = false);
void ReplaceGateToSubCfg(GateRef gate, GateRef state, GateRef depend, GateRef value);
void ReplaceHirToFastPathCfg(GateRef hir, GateRef outir, const std::vector<GateRef> &successControl);
void LowerNumberInc(GateRef gate);
void LowerNumberDec(GateRef gate);
void ReplaceGate(GateRef gate, GateRef state, GateRef depend, GateRef value);
GateRef LowerCallRuntime(GateRef glue, int index, const std::vector<GateRef> &args, bool useLabel = false);
template<OpCode::Op Op>
GateRef FastAddOrSubOrMul(GateRef left, GateRef right);
template<OpCode::Op Op>
GateRef CalculateNumbers(GateRef left, GateRef right);
GateRef CalculateNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType);
template<TypedBinOp Op>
GateRef CompareNumbers(GateRef left, GateRef right);
GateRef CompareNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType);
template<TypedBinOp Op>
GateRef CompareInt(GateRef left, GateRef right);
template<TypedBinOp Op>
GateRef CompareDouble(GateRef left, GateRef right);
template<TypedUnOp Op>
GateRef MonocularNumber(GateRef value, GateType valueType);
template<OpCode::Op Op, MachineType Type>
GateRef BinaryOp(GateRef x, GateRef y);
GateRef DoubleToTaggedDoublePtr(GateRef gate);
GateRef ChangeInt32ToFloat64(GateRef gate);
GateRef GeneralMod(GateRef left, GateRef right, GateRef glue);
GateRef ModNumbers(GateRef left, GateRef right);
GateRef Int32Mod(GateRef left, GateRef right);
GateRef DoubleMod(GateRef left, GateRef right);
GateRef IntToTaggedIntPtr(GateRef x);
@ -172,23 +179,8 @@ private:
GateRef Less(GateRef left, GateRef right);
GateRef LessEq(GateRef left, GateRef right);
GateRef FastDiv(GateRef left, GateRef right);
GateRef DivNumbers(GateRef left, GateRef right);
GateRef DivNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType);
GateRef FastEqual(GateRef left, GateRef right);
void LowerTypeAdd(GateRef gate, GateRef glue);
void LowerTypeSub(GateRef gate);
void LowerTypeMul(GateRef gate);
void LowerTypeMod(GateRef gate, GateRef glue);
void LowerTypeLess(GateRef gate);
void LowerTypeLessEq(GateRef gate);
void LowerTypeGreater(GateRef gate);
void LowerTypeGreaterEq(GateRef gate);
void LowerTypeDiv(GateRef gate);
void LowerTypeEq(GateRef gate);
void LowerTypeNotEq(GateRef gate);
void LowerToNumeric(GateRef gate);
void LowerTypeInc(GateRef gate);
GateType GetLeftType(GateRef gate);
GateType GetRightType(GateRef gate);
@ -199,6 +191,7 @@ private:
GateRef dependEntry_;
[[maybe_unused]] TSManager *tsManager_ {nullptr};
bool enableLog_ {false};
std::string methodName_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_TYPE_LOWERING_H

View File

@ -422,11 +422,11 @@ std::vector<GateRef> Verifier::FindFixedGates(const Circuit *circuit, const std:
return fixedGatesList;
}
bool Verifier::Run(const Circuit *circuit, bool enableLog)
bool Verifier::Run(const Circuit *circuit, const std::string& methodName, bool enableLog)
{
if (!RunDataIntegrityCheck(circuit)) {
if (enableLog) {
LOG_COMPILER(ERROR) << "[Verifier][Fail] Circuit data integrity verifier failed";
LOG_COMPILER(ERROR) << "[Verifier][Fail] Circuit data integrity verifier failed, " << methodName;
}
return false;
}

View File

@ -28,28 +28,40 @@ namespace panda::ecmascript::kungfu {
class Verifier {
public:
static bool RunDataIntegrityCheck(const Circuit *circuit);
static bool RunStateGatesCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList);
static bool RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx);
static bool RunCFGIsDAGCheck(const Circuit *circuit);
static bool RunCFGReducibilityCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
const std::function<bool(size_t, size_t)> &isAncestor);
static bool RunFixedGatesCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList);
static bool RunFixedGatesRelationsCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
const std::function<bool(size_t, size_t)> &isAncestor);
static bool RunFlowCyclesFind(const Circuit *circuit, std::vector<GateRef> *schedulableGatesListPtr,
const std::vector<GateRef> &bbGatesList,
const std::vector<GateRef> &fixedGatesList);
static bool RunSchedulableGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList);
static bool RunPrologGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList);
static bool RunSchedulingBoundsCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList,
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
const std::function<bool(size_t, size_t)> &isAncestor,
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor);
static std::vector<GateRef> FindFixedGates(const Circuit *circuit, const std::vector<GateRef> &bbGatesList);
static bool Run(const Circuit *circuit, bool enableLog = false);
static bool Run(const Circuit *circuit, const std::string& methodName = "", bool enableLog = false);
};
} // namespace panda::ecmascript::kungfu

225
ecmascript/deoptimizer.cpp Normal file
View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 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 "deoptimizer.h"
#include "ecmascript/compiler/assembler/assembler.h"
#include "ecmascript/frames.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/stubs/runtime_stubs-inl.h"
namespace panda::ecmascript {
using DeoptFromAOTType = JSTaggedType (*)(uintptr_t glue, JSTaggedType* sp,
uintptr_t vregsSp, uintptr_t stateSp, JSTaggedType callTarget);
static constexpr size_t LEXENV_INDEX = 1;
static constexpr size_t THIS_VALUE_INDEX = 5;
class FrameWriter {
public:
explicit FrameWriter(Deoptimizier *deoptimizier) : thread_(deoptimizier->GetThread())
{
JSTaggedType *prevSp = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
start_ = top_ = EcmaInterpreter::GetInterpreterFrameEnd(thread_, prevSp);
}
void PushValue(JSTaggedType value)
{
*(--top_) = value;
}
void PushRawValue(uintptr_t value)
{
*(--top_) = value;
}
bool Reserve(size_t size)
{
return !thread_->DoStackOverflowCheck(top_ - size);
}
AsmInterpretedFrame *ReserveAsmInterpretedFrame()
{
auto frame = AsmInterpretedFrame::GetFrameFromSp(top_);
top_ = reinterpret_cast<JSTaggedType *>(frame);
return frame;
}
JSTaggedType *GetStart() const
{
return start_;
}
JSTaggedType *GetTop() const
{
return top_;
}
private:
JSThread *thread_ {nullptr};
JSTaggedType *start_;
JSTaggedType *top_;
};
void Deoptimizier::CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle)
{
vregs_.clear();
for (size_t i = 0; i < deoptBundle.size(); i++) {
kungfu::ARKDeopt deopt = deoptBundle.at(i);
JSTaggedType v;
kungfu::OffsetType id = deopt.Id;
if (std::holds_alternative<kungfu::DwarfRegAndOffsetType>(deopt.value)) {
ASSERT(deopt.kind == kungfu::LocationTy::Kind::INDIRECT);
auto value = std::get<kungfu::DwarfRegAndOffsetType>(deopt.value);
kungfu::DwarfRegType dwarfReg = value.first;
kungfu::OffsetType offset = value.second;
ASSERT (dwarfReg == GCStackMapRegisters::FP || dwarfReg == GCStackMapRegisters::SP);
uintptr_t addr;
if (dwarfReg == GCStackMapRegisters::SP) {
addr = context_.callsiteSp + offset;
} else {
addr = context_.callsiteFp + offset;
}
v = *(reinterpret_cast<JSTaggedType *>(addr));
} else if (std::holds_alternative<kungfu::LargeInt>(deopt.value)) {
ASSERT(deopt.kind == kungfu::LocationTy::Kind::CONSTANTNDEX);
v = JSTaggedType(static_cast<int64_t>(std::get<kungfu::LargeInt>(deopt.value)));
} else {
ASSERT(std::holds_alternative<kungfu::OffsetType>(deopt.value));
ASSERT(deopt.kind == kungfu::LocationTy::Kind::CONSTANT);
v = JSTaggedType(static_cast<int64_t>(std::get<kungfu::OffsetType>(deopt.value)));
}
if (id != static_cast<kungfu::OffsetType>(SpecVregIndex::PC_INDEX)) {
vregs_[id] = JSTaggedValue(v);
} else {
pc_ = static_cast<uint32_t>(v);
}
}
}
void Deoptimizier::CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle)
{
JSTaggedType *lastLeave = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
FrameIterator it(lastLeave, thread_);
for (; !it.Done() && deoptBundle.empty(); it.Advance<GCVisitedFlag::VISITED>()) {
FrameType type = it.GetFrameType();
switch (type) {
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
frame->GetDeoptBundleInfo(it, deoptBundle);
kungfu::CalleeRegAndOffsetVec calleeRegInfo;
frame->GetFuncCalleeRegAndOffset(it, calleeRegInfo);
context_.calleeRegAndOffset = calleeRegInfo;
context_.callsiteSp = it.GetCallSiteSp();
context_.callsiteFp = reinterpret_cast<uintptr_t>(it.GetSp());
context_.preFrameSp = frame->ComputePrevFrameSp(it);
context_.returnAddr = frame->GetReturnAddr();
uint64_t argc = frame->GetArgc(context_.preFrameSp);
auto argv = frame->GetArgv(reinterpret_cast<uintptr_t *>(context_.preFrameSp));
if (argc > 0) {
ASSERT(argc >= FIXED_NUM_ARGS);
callTarget_ = JSTaggedValue(argv[0]);
}
AotArgvs_ = argv;
stackContext_.callFrameTop_ = it.GetPrevFrameCallSiteSp();
stackContext_.returnAddr_ = context_.returnAddr;
stackContext_.callerFp_ = reinterpret_cast<uintptr_t>(frame->GetPrevFrameFp());
break;
}
case FrameType::OPTIMIZED_FRAME: {
auto sp = reinterpret_cast<uintptr_t*>(it.GetSp());
sp--; // skip type
calleeRegAddr_ = sp - numCalleeRegs_;
break;
}
case FrameType::LEAVE_FRAME:
break;
default: {
LOG_ECMA(FATAL) << "frame type error!";
UNREACHABLE();
}
}
}
ASSERT(!it.Done());
}
Method* Deoptimizier::GetMethod(JSTaggedValue &target)
{
ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(target.GetTaggedObject());
ASSERT(callTarget != nullptr);
Method *method = callTarget->GetCallTarget();
return method;
}
void Deoptimizier::RelocateCalleeSave()
{
kungfu::CalleeReg callreg;
for (auto &it: context_.calleeRegAndOffset) {
auto reg = it.first;
auto offset = it.second;
uintptr_t value = *(reinterpret_cast<uintptr_t *>(context_.callsiteFp + offset));
int order = callreg.FindCallRegOrder(reg);
calleeRegAddr_[order] = value;
}
}
JSTaggedType Deoptimizier::ConstructAsmInterpretFrame()
{
ASSERT(thread_ != nullptr);
auto fun = callTarget_;
FrameWriter frameWriter(this);
// Push asm interpreter frame
auto method = GetMethod(callTarget_);
auto numVRegs = method->GetNumberVRegs();
if (!frameWriter.Reserve(numVRegs)) {
return JSTaggedValue::Exception().GetRawData();
}
for (int32_t i = numVRegs - 1; i >= 0; i--) {
JSTaggedValue value = JSTaggedValue::Undefined();
if (vregs_.find(static_cast<kungfu::OffsetType>(i)) != vregs_.end()) {
value = vregs_.at(static_cast<kungfu::OffsetType>(i));
}
frameWriter.PushValue(value.GetRawData());
}
const uint8_t *resumePc = method->GetBytecodeArray() + pc_;
AsmInterpretedFrame *statePtr = frameWriter.ReserveAsmInterpretedFrame();
JSTaggedValue env = JSTaggedValue(GetArgv(LEXENV_INDEX));
JSTaggedValue thisObj = JSTaggedValue(GetArgv(THIS_VALUE_INDEX));
auto acc = vregs_.at(static_cast<kungfu::OffsetType>(SpecVregIndex::ACC_INDEX));
statePtr->function = fun;
statePtr->acc = acc;
statePtr->env = env;
statePtr->callSize = 0;
statePtr->fp = 0; // need update
statePtr->thisObj = thisObj;
statePtr->pc = resumePc;
// -uintptr_t skip lr
statePtr->base.prev = reinterpret_cast<JSTaggedType *>(
stackContext_.callFrameTop_ - sizeof(uintptr_t));
statePtr->base.type = FrameType::ASM_INTERPRETER_FRAME;
// construct stack context
auto start = frameWriter.GetStart();
auto end = frameWriter.GetTop();
auto outputCount = start - end;
RelocateCalleeSave();
frameWriter.PushRawValue(stackContext_.callerFp_);
frameWriter.PushRawValue(stackContext_.returnAddr_);
frameWriter.PushRawValue(stackContext_.callFrameTop_);
frameWriter.PushRawValue(outputCount);
return reinterpret_cast<JSTaggedType>(frameWriter.GetTop());
}
} // namespace panda::ecmascript

127
ecmascript/deoptimizer.h Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 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.
*/
#ifndef ECMASCRIPT_DEOPTIMIZER_H
#define ECMASCRIPT_DEOPTIMIZER_H
#include "ecmascript/base/aligned_struct.h"
#include "ecmascript/calleeReg.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/llvm_stackmap_type.h"
// todo:place to Deoptimizier class
#define LLVM_DEOPT_RELOCATE_SYMBOL "__llvm_deoptimize"
namespace panda::ecmascript {
class JSThread;
enum class SpecVregIndex: int {
PC_INDEX = -1,
ACC_INDEX = -2,
BC_OFFSET_INDEX = -3,
};
struct Context {
uintptr_t callsiteSp;
uintptr_t callsiteFp;
uintptr_t* preFrameSp;
uintptr_t returnAddr;
kungfu::CalleeRegAndOffsetVec calleeRegAndOffset;
};
struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(),
base::AlignedPointer,
base::AlignedPointer,
base::AlignedPointer,
base::AlignedPointer> {
enum class Index : size_t {
OUTPUT_COUNT_INDEX = 0,
CALLFRAME_TOP_INDEX,
RETURN_ADDRESS_INDEX,
CALLERFRAME_POINTER_INDEX,
NUM_OF_MEMBER
};
static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes);
static size_t GetOutputCountOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::OUTPUT_COUNT_INDEX)>(isArch32);
}
static size_t GetCallFrameTopOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32);
}
static size_t GetReturnAddressOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32);
}
static size_t GetCallerFpOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32);
}
static constexpr size_t GetSize(bool isArch32)
{
return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64;
}
alignas(EAS) size_t outputCount_ {0};
alignas(EAS) uintptr_t callFrameTop_{0};
alignas(EAS) uintptr_t returnAddr_{0};
alignas(EAS) uintptr_t callerFp_{0};
// out put data
};
class Deoptimizier {
public:
static constexpr uint64_t LLVM_DEOPT_RELOCATE_ADDR = 0xabcdef0f;
explicit Deoptimizier(JSThread * thread) : thread_(thread)
{
kungfu::CalleeReg callreg;
numCalleeRegs_ = callreg.GetCallRegNum();
}
void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle);
void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle);
JSTaggedType ConstructAsmInterpretFrame();
JSTaggedType GetArgv(int idx)
{
ASSERT(AotArgvs_ != nullptr);
return AotArgvs_[static_cast<int>(idx)];
}
JSThread *GetThread() const
{
return thread_;
}
private:
Method* GetMethod(JSTaggedValue &target);
void RelocateCalleeSave();
JSThread *thread_ {nullptr};
uintptr_t *calleeRegAddr_ {nullptr};
size_t numCalleeRegs_ {0};
AsmStackContext stackContext_;
std::unordered_map<kungfu::OffsetType, JSTaggedValue> vregs_;
struct Context context_ {0, 0, nullptr, 0, {}};
uint32_t pc_;
JSTaggedValue callTarget_ {JSTaggedValue::Undefined()};
JSTaggedType *AotArgvs_ {nullptr};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_DEOPTIMIZER_H

View File

@ -537,29 +537,7 @@ bool CpuProfiler::IsAddrAtStub(void *context)
return true;
#endif
FileLoader *loader = vm_->GetFileLoader();
if (loader == nullptr) {
return false;
}
const StubModulePackInfo &stubPackInfo = loader->GetStubPackInfo();
uint64_t stubStartAddr = stubPackInfo.GetAsmStubAddr();
uint64_t stubEndAddr = stubStartAddr + stubPackInfo.GetAsmStubSize();
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
const std::vector<ModuleSectionDes> &des = stubPackInfo.GetCodeUnits();
stubStartAddr = des[0].GetSecAddr(ElfSecName::TEXT);
stubEndAddr = stubStartAddr + des[0].GetSecSize(ElfSecName::TEXT);
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
stubStartAddr = des[1].GetSecAddr(ElfSecName::TEXT);
stubEndAddr = stubStartAddr + des[1].GetSecSize(ElfSecName::TEXT);
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
return false;
return loader->InsideStub(pc);
}
std::string CpuProfiler::GetProfileName() const

View File

@ -769,11 +769,10 @@ void EcmaVM::LoadStubFile()
void EcmaVM::LoadAOTFiles()
{
std::string anFile = options_.GetAOTOutputFile() + ".an";
LOG_ECMA(INFO) << "Try to load an file" << anFile.c_str();
fileLoader_->LoadAOTFile(anFile);
fileLoader_->RewriteGotSection();
std::string etsoFile = options_.GetAOTOutputFile() + ".etso";
LOG_ECMA(INFO) << "Try to load etso file" << etsoFile.c_str();
fileLoader_->LoadSnapshotFile(etsoFile);
}

View File

@ -22,6 +22,7 @@
#include "ecmascript/base/config.h"
#include "ecmascript/compiler/bc_call_signature.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/llvm_stackmap_parser.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/message_string.h"
@ -38,6 +39,9 @@ extern const uint8_t _binary_stub_an_start[];
extern const uint32_t _binary_stub_an_length;
namespace panda::ecmascript {
using CommonStubCSigns = kungfu::CommonStubCSigns;
using BytecodeStubCSigns = kungfu::BytecodeStubCSigns;
void ModuleSectionDes::SaveSectionsInfo(std::ofstream &file)
{
uint32_t secInfoSize = GetSecInfosSize();
@ -199,7 +203,7 @@ bool StubModulePackInfo::Load(EcmaVM *vm)
entry.codeAddr_ += moduleDes.GetSecAddr(ElfSecName::TEXT);
}
}
LOG_COMPILER(INFO) << "Load stub file success";
LOG_COMPILER(INFO) << "loaded stub file successfully";
return true;
}
@ -226,11 +230,13 @@ bool AOTModulePackInfo::Load(EcmaVM *vm, const std::string &filename)
{
if (!VerifyFilePath(filename)) {
LOG_COMPILER(ERROR) << "Can not load aot file from path [ " << filename << " ], "
<< "please execute ark_aot_compiler with options --aot-file.";
<< "please execute ark_aot_compiler with options --aot-file.";
UNREACHABLE();
return false;
}
std::ifstream file(filename.c_str(), std::ofstream::binary);
if (!file.good()) {
LOG_COMPILER(ERROR) << "Fail to load aot file: " << filename.c_str();
file.close();
return false;
}
@ -253,14 +259,15 @@ bool AOTModulePackInfo::Load(EcmaVM *vm, const std::string &filename)
des_[i].LoadSectionsInfo(file, curUnitOffset, codeAddress);
}
for (size_t i = 0; i < entries_.size(); i++) {
auto des = des_[entries_[i].moduleIndex_];
entries_[i].codeAddr_ += des.GetSecAddr(ElfSecName::TEXT);
auto curFileHash = aotFileHashs_[entries_[i].moduleIndex_];
auto curMethodId = entries_[i].indexInKind_;
vm->GetFileLoader()->SaveAOTFuncEntry(curFileHash, curMethodId, entries_[i].codeAddr_);
FuncEntryDes& funcDes = entries_[i];
auto moduleDes = des_[funcDes.moduleIndex_];
funcDes.codeAddr_ += moduleDes.GetSecAddr(ElfSecName::TEXT);
auto curFileHash = aotFileHashs_[funcDes.moduleIndex_];
auto curMethodId = funcDes.indexInKind_;
vm->GetFileLoader()->SaveAOTFuncEntry(curFileHash, curMethodId, funcDes.codeAddr_);
}
file.close();
LOG_COMPILER(INFO) << "Load aot file success";
LOG_COMPILER(INFO) << "loaded aot file: " << filename.c_str();
return true;
}
@ -334,12 +341,67 @@ void FileLoader::UpdateJSMethods(JSHandle<JSFunction> mainFunc, const JSPandaFil
mainMethod->SetNativeBit(false);
Method *method = mainFunc->GetCallTarget();
method->SetCodeEntryAndMarkAOT(reinterpret_cast<uintptr_t>(mainEntry));
#ifndef NDEBUG
PrintAOTEntry(jsPandaFile, method, mainEntry);
#endif
}
bool FileLoader::InsideStub(uint64_t pc) const
{
uint64_t stubStartAddr = stubPackInfo_.GetAsmStubAddr();
uint64_t stubEndAddr = stubStartAddr + stubPackInfo_.GetAsmStubSize();
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
const std::vector<ModuleSectionDes> &des = stubPackInfo_.GetCodeUnits();
stubStartAddr = des[0].GetSecAddr(ElfSecName::TEXT);
stubEndAddr = stubStartAddr + des[0].GetSecSize(ElfSecName::TEXT);
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
stubStartAddr = des[1].GetSecAddr(ElfSecName::TEXT);
stubEndAddr = stubStartAddr + des[1].GetSecSize(ElfSecName::TEXT);
if (pc >= stubStartAddr && pc <= stubEndAddr) {
return true;
}
return false;
}
ModulePackInfo::CallSiteInfo FileLoader::CalCallSiteInfo(uintptr_t retAddr) const
{
ModulePackInfo::CallSiteInfo callsiteInfo;
bool ans = stubPackInfo_.CalCallSiteInfo(retAddr, callsiteInfo);
if (ans) {
return callsiteInfo;
}
// aot
for (auto &info : aotPackInfos_) {
ans = info.CalCallSiteInfo(retAddr, callsiteInfo);
if (ans) {
return callsiteInfo;
}
}
return callsiteInfo;
}
void FileLoader::PrintAOTEntry(const JSPandaFile *file, const Method *method, uintptr_t entry)
{
uint32_t mId = method->GetMethodId().GetOffset();
std::string mName = method->GetMethodName(file);
std::string fileName = file->GetFileName();
LOG_COMPILER(INFO) << "Bind " << mName << "@" << mId << "@" << fileName
<< " -> AOT-Entry = " << reinterpret_cast<void*>(entry);
}
void FileLoader::SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method)
{
uint32_t methodId = method->GetMethodId().GetOffset();
auto codeEntry = GetAOTFuncEntry(jsPandaFile->GetFileUniqId(), methodId);
#ifndef NDEBUG
PrintAOTEntry(jsPandaFile, method, codeEntry);
#endif
if (!codeEntry) {
return;
}
@ -430,14 +492,37 @@ bool FileLoader::RewriteDataSection(uintptr_t dataSec, size_t size,
return true;
}
void FileLoader::RuntimeRelocate()
bool FileLoader::RewriteGotSection()
{
auto desVector = stubPackInfo_.GetModuleSectionDes();
for (auto &des : desVector) {
auto dataSec = des.GetSecAddr(ElfSecName::DATA);
auto dataSecSize = des.GetSecSize(ElfSecName::DATA);
(void)RewriteDataSection(dataSec, dataSecSize, 0, 0);
auto fn = [&](const ModuleSectionDes& d) {
uintptr_t addr = d.GetSecAddr(ElfSecName::GOT);
uint32_t size = d.GetSecSize(ElfSecName::GOT);
if (size == 0) {
return true;
}
// only support __llvm_deoptimize is undefined
if (size != sizeof(uintptr_t)) {
LOG_FULL(FATAL) << "more than one function/data is undefined failed";
return false;
}
auto thread = vm_->GetAssociatedJSThread();
uintptr_t ptr = thread->GetRTInterface(RTSTUB_ID(DeoptHandlerAsm));
*(reinterpret_cast<uintptr_t *>(addr)) = ptr;
return true;
};
// aot
bool ans = false;
for (auto &info : aotPackInfos_) {
auto& des = info.GetCodeUnits();
for (size_t i = 0; i < des.size(); i++) {
auto d = des[i];
ans = fn(d);
if (!ans) {
return ans;
}
}
}
return ans;
}
FileLoader::~FileLoader()
@ -530,7 +615,8 @@ void BinaryBufferParser::ParseBuffer(uint8_t *dst, uint32_t count, uint8_t *src)
}
}
bool ModulePackInfo::CalCallSiteInfo(uintptr_t retAddr, std::tuple<uint64_t, uint8_t *, int>& ret) const
bool ModulePackInfo::CalCallSiteInfo(uintptr_t retAddr,
std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec>& ret) const
{
uint64_t textStart = 0;
uint8_t *stackmapAddr = nullptr;
@ -562,9 +648,16 @@ bool ModulePackInfo::CalCallSiteInfo(uintptr_t retAddr, std::tuple<uint64_t, uin
ASSERT(it != t);
ASSERT((it->codeAddr_ <= target.codeAddr_) && (target.codeAddr_ < it->codeAddr_ + it->funcSize_));
delta = it->fpDeltaPrevFrameSp_;
ret = std::make_tuple(textStart, stackmapAddr, delta);
kungfu::CalleeRegAndOffsetVec calleeRegInfo;
for (uint32_t j = 0; j < it->calleeRegisterNum_; j++) {
kungfu::DwarfRegType reg = static_cast<kungfu::DwarfRegType>(it->CalleeReg2Offset_[2 * j]);
kungfu::OffsetType offset = static_cast<kungfu::OffsetType>(it->CalleeReg2Offset_[2 * j + 1]);
kungfu::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset);
calleeRegInfo.emplace_back(regAndOffset);
}
ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo);
return true;
}
return false;
}
}
}

View File

@ -15,6 +15,8 @@
#ifndef ECMASCRIPT_COMPILER_FILE_LOADER_H
#define ECMASCRIPT_COMPILER_FILE_LOADER_H
#include "ecmascript/ark_stackmap.h"
#include "ecmascript/calleeReg.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_runtime_options.h"
#include "ecmascript/compiler/binary_section.h"
@ -22,9 +24,6 @@
namespace panda::ecmascript {
class JSpandafile;
class JSThread;
namespace kungfu {
class LLVMStackMapParser;
};
class BinaryBufferParser {
public:
@ -43,9 +42,6 @@ struct ModuleSectionDes {
std::map<ElfSecName, std::pair<uint64_t, uint32_t>> sectionsInfo_ {};
uint32_t startIndex_ {static_cast<uint32_t>(-1)}; // record current module first function index in PackInfo
uint32_t funcCount_ {0};
/* arkStackMapPtr_: generator aot file, stackmap buffer lifecycle is managned by share ptr
while arkStackMapRawPtr_ is allocated by machinecode, lifecycle is managned by machinecode.
*/
std::shared_ptr<uint8_t> arkStackMapPtr_ {nullptr};
uint32_t arkStackMapSize_ {0};
uint8_t *arkStackMapRawPtr_ {nullptr};
@ -109,7 +105,8 @@ struct ModuleSectionDes {
uint64_t GetSecAddr(const ElfSecName idx) const
{
return sectionsInfo_.at(idx).first;
auto it = sectionsInfo_.find(idx);
return it == sectionsInfo_.end() ? 0 : it->second.first;
}
void EraseSec(ElfSecName idx)
@ -124,7 +121,8 @@ struct ModuleSectionDes {
uint32_t GetSecSize(const ElfSecName idx) const
{
return sectionsInfo_.at(idx).second;
auto it = sectionsInfo_.find(idx);
return it == sectionsInfo_.end() ? 0 : it->second.second;
}
uint32_t GetSecInfosSize()
@ -149,12 +147,14 @@ public:
bool VerifyFilePath([[maybe_unused]] const std::string &filePath, [[maybe_unused]] bool toGenerate = false) const;
struct FuncEntryDes {
uint64_t codeAddr_ {0};
CallSignature::TargetKind kind_ {CallSignature::TargetKind::COMMON_STUB};
uint32_t indexInKind_ {0};
uint32_t moduleIndex_ {0};
int fpDeltaPrevFrameSp_ {0};
uint32_t funcSize_ {0};
uint64_t codeAddr_;
CallSignature::TargetKind kind_;
uint32_t indexInKind_;
uint32_t moduleIndex_;
int fpDeltaPrevFrameSp_;
uint32_t funcSize_;
[[maybe_unused]] uint32_t calleeRegisterNum_;
int32_t CalleeReg2Offset_[2 * kungfu::MAX_CALLEE_SAVE_REIGISTER_NUM];
bool IsStub() const
{
return CallSignature::TargetKind::STUB_BEGIN <= kind_ && kind_ < CallSignature::TargetKind::STUB_END;
@ -184,7 +184,7 @@ public:
bool IsGeneralRTStub() const
{
return (kind_ >= CallSignature::TargetKind::RUNTIME_STUB &&
kind_ <= CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
kind_ <= CallSignature::TargetKind::DEOPT_STUB);
}
};
@ -236,7 +236,7 @@ public:
}
void AddStubEntry(CallSignature::TargetKind kind, int indexInKind, uint64_t offset,
uint32_t moduleIndex, int delta, uint32_t size)
uint32_t moduleIndex, int delta, uint32_t size, kungfu::CalleeRegAndOffsetVec info = {})
{
FuncEntryDes des;
if (memset_s(&des, sizeof(des), 0, sizeof(des)) != EOK) {
@ -249,6 +249,14 @@ public:
des.moduleIndex_ = moduleIndex;
des.fpDeltaPrevFrameSp_ = delta;
des.funcSize_ = size;
des.calleeRegisterNum_ = info.size();
kungfu::DwarfRegType reg = 0;
kungfu::OffsetType regOffset = 0;
for (size_t i = 0; i < info.size(); i ++) {
std::tie(reg, regOffset) = info[i];
des.CalleeReg2Offset_[2 * i] = static_cast<int32_t>(reg);
des.CalleeReg2Offset_[2 * i + 1] = static_cast<int32_t>(regOffset);
}
entries_.emplace_back(des);
}
@ -266,7 +274,10 @@ public:
{
totalCodeSize_ += size;
}
bool CalCallSiteInfo(uintptr_t retAddr, std::tuple<uint64_t, uint8_t *, int>& ret) const;
using CallSiteInfo = std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec>;
bool CalCallSiteInfo(uintptr_t retAddr, CallSiteInfo& ret) const;
protected:
uint32_t entryNum_ {0};
uint32_t moduleNum_ {0};
@ -297,6 +308,7 @@ public:
accumulateTotalSize(moduleDes.GetArkStackMapSize());
aotFileHashs_.emplace_back(hash);
}
private:
std::vector<uint32_t> aotFileHashs_ {};
};
@ -363,25 +375,14 @@ private:
};
class FileLoader {
using CommonStubCSigns = kungfu::CommonStubCSigns;
using BytecodeStubCSigns = kungfu::BytecodeStubCSigns;
public:
explicit FileLoader(EcmaVM *vm);
virtual ~FileLoader();
void LoadStubFile();
void LoadAOTFile(const std::string &fileName);
void SetAOTmmap(void *addr, size_t totalCodeSize)
{
aotAddrs_.emplace_back(std::make_pair(addr, totalCodeSize));
}
void SetStubmmap(void *addr, size_t totalCodeSize)
{
stubAddrs_.emplace_back(std::make_pair(addr, totalCodeSize));
}
void AddAOTPackInfo(AOTModulePackInfo packInfo)
{
aotPackInfos_.emplace_back(packInfo);
}
ModulePackInfo::CallSiteInfo CalCallSiteInfo(uintptr_t retAddr) const;
bool InsideStub(uint64_t pc) const;
void Iterate(const RootVisitor &v)
{
if (!stubPackInfo_.isCodeHole()) {
@ -399,26 +400,6 @@ public:
hashToEntryMap_[hash][methodId] = funcEntry;
}
uintptr_t GetAOTFuncEntry(uint32_t hash, uint32_t methodId)
{
auto m = hashToEntryMap_[hash];
auto it = m.find(methodId);
if (it == m.end()) {
return 0;
}
return static_cast<uintptr_t>(it->second);
}
const StubModulePackInfo& GetStubPackInfo() const
{
return stubPackInfo_;
}
const std::vector<AOTModulePackInfo>& GetPackInfos() const
{
return aotPackInfos_;
}
void UpdateJSMethods(JSHandle<JSFunction> mainFunc, const JSPandaFile *jsPandaFile);
bool hasLoaded(const JSPandaFile *jsPandaFile);
void SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method);
@ -428,10 +409,44 @@ public:
static JSTaggedValue GetAbsolutePath(JSThread *thread, JSTaggedValue relativePathVal);
static bool GetAbsolutePath(const std::string &relativePath, std::string &absPath);
static bool GetAbsolutePath(const CString &relativePathCstr, CString &absPathCstr);
bool RewriteDataSection(uintptr_t dataSec, size_t size, uintptr_t newData, size_t newSize);
void RuntimeRelocate();
bool RewriteGotSection();
private:
void SetAOTmmap(void *addr, size_t totalCodeSize)
{
aotAddrs_.emplace_back(std::make_pair(addr, totalCodeSize));
}
void SetStubmmap(void *addr, size_t totalCodeSize)
{
stubAddrs_.emplace_back(std::make_pair(addr, totalCodeSize));
}
const StubModulePackInfo& GetStubPackInfo() const
{
return stubPackInfo_;
}
void AddAOTPackInfo(AOTModulePackInfo packInfo)
{
aotPackInfos_.emplace_back(packInfo);
}
uintptr_t GetAOTFuncEntry(uint32_t hash, uint32_t methodId)
{
auto m = hashToEntryMap_[hash];
auto it = m.find(methodId);
if (it == m.end()) {
return 0;
}
return static_cast<uintptr_t>(it->second);
}
void PrintAOTEntry(const JSPandaFile *file, const Method *method, uintptr_t entry);
void InitializeStubEntries(const std::vector<AOTModulePackInfo::FuncEntryDes>& stubs);
void AdjustBCStubAndDebuggerStubEntries(JSThread *thread, const std::vector<ModulePackInfo::FuncEntryDes> &stubs,
const AsmInterParsedOption &asmInterOpt);
std::vector<std::pair<void *, size_t>> aotAddrs_;
std::vector<std::pair<void *, size_t>> stubAddrs_;
EcmaVM *vm_ {nullptr};
@ -441,9 +456,8 @@ private:
std::unordered_map<uint32_t, std::unordered_map<uint32_t, uint64_t>> hashToEntryMap_ {};
kungfu::ArkStackMapParser *arkStackMapParser_ {nullptr};
void InitializeStubEntries(const std::vector<AOTModulePackInfo::FuncEntryDes>& stubs);
void AdjustBCStubAndDebuggerStubEntries(JSThread *thread, const std::vector<ModulePackInfo::FuncEntryDes> &stubs,
const AsmInterParsedOption &asmInterOpt);
friend class AOTModulePackInfo;
friend class StubModulePackInfo;
};
}
#endif // ECMASCRIPT_COMPILER_FILE_LOADER_H
#endif // ECMASCRIPT_COMPILER_FILE_LOADER_H

View File

@ -48,25 +48,10 @@ int FrameIterator::GetCallSiteDelta(uintptr_t returnAddr) const
return delta;
}
std::tuple<uint64_t, uint8_t *, int> FrameIterator::CalCallSiteInfo(uintptr_t retAddr) const
ModulePackInfo::CallSiteInfo FrameIterator::CalCallSiteInfo(uintptr_t retAddr) const
{
auto loader = thread_->GetEcmaVM()->GetFileLoader();
const std::vector<AOTModulePackInfo>& aotPackInfos = loader->GetPackInfos();
std::tuple<uint64_t, uint8_t *, int> callsiteInfo;
StubModulePackInfo stubInfo = loader->GetStubPackInfo();
bool ans = stubInfo.CalCallSiteInfo(retAddr, callsiteInfo);
if (ans) {
return callsiteInfo;
}
// aot
for (auto &info : aotPackInfos) {
ans = info.CalCallSiteInfo(retAddr, callsiteInfo);
if (ans) {
return callsiteInfo;
}
}
return callsiteInfo;
return loader->CalCallSiteInfo(retAddr);
}
template <GCVisitedFlag GCVisit>
@ -242,7 +227,7 @@ void FrameIterator::Advance()
return;
}
uint64_t textStart;
std::tie(textStart, stackMapAddr_, fpDeltaPrevFrameSp_) = CalCallSiteInfo(optimizedReturnAddr_);
std::tie(textStart, stackMapAddr_, fpDeltaPrevFrameSp_, calleeRegInfo_) = CalCallSiteInfo(optimizedReturnAddr_);
ASSERT(optimizedReturnAddr_ >= textStart);
optimizedReturnAddr_ = optimizedReturnAddr_ - textStart;
}
@ -365,6 +350,11 @@ void FrameIterator::CollectBCOffsetInfo(kungfu::ConstInfo &info) const
arkStackMapParser_->GetConstInfo(optimizedReturnAddr_, info, stackMapAddr_);
}
void FrameIterator::CollectArkDeopt(std::vector<kungfu::ARKDeopt>& deopts) const
{
arkStackMapParser_->GetArkDeopt(optimizedReturnAddr_, stackMapAddr_, deopts);
}
ARK_INLINE JSTaggedType* OptimizedJSFunctionFrame::GetArgv(const FrameIterator &it) const
{
uintptr_t *preFrameSp = ComputePrevFrameSp(it);
@ -415,6 +405,17 @@ ARK_INLINE void OptimizedJSFunctionFrame::GCIterate(const FrameIterator &it,
}
}
void OptimizedJSFunctionFrame::GetDeoptBundleInfo(const FrameIterator &it, std::vector<kungfu::ARKDeopt>& deopts) const
{
it.CollectArkDeopt(deopts);
}
void OptimizedJSFunctionFrame::GetFuncCalleeRegAndOffset(
const FrameIterator &it, kungfu::CalleeRegAndOffsetVec &ret) const
{
it.GetCalleeRegAndOffsetVec(ret);
}
ARK_INLINE void AsmInterpretedFrame::GCIterate(const FrameIterator &it,
const RootVisitor &visitor,
const RootRangeVisitor &rangeVisitor,

View File

@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_FRAMES_H
#define ECMASCRIPT_FRAMES_H
#include "ecmascript/ark_stackmap.h"
#include "ecmascript/js_tagged_value.h"
// Frame Layout
@ -476,7 +477,6 @@ public:
{
return prevFp;
}
uintptr_t* ComputePrevFrameSp(const FrameIterator &it) const;
JSTaggedType* GetArgv(uintptr_t *preFrameSp) const
{
@ -520,13 +520,17 @@ public:
return MEMBER_OFFSET(OptimizedJSFunctionFrame, prevFp);
}
friend class FrameIterator;
void GetDeoptBundleInfo(const FrameIterator &it, std::vector<kungfu::ARKDeopt>& deopts) const;
void GetFuncCalleeRegAndOffset(
const FrameIterator &it, kungfu::CalleeRegAndOffsetVec &ret) const;
uintptr_t* ComputePrevFrameSp(const FrameIterator &it) const;
private:
static OptimizedJSFunctionFrame* GetFrameFromSp(const JSTaggedType *sp)
{
return reinterpret_cast<OptimizedJSFunctionFrame *>(reinterpret_cast<uintptr_t>(sp)
- MEMBER_OFFSET(OptimizedJSFunctionFrame, prevFp));
}
// dynamic callee saveregisters for x86-64
alignas(EAS) JSTaggedValue env {JSTaggedValue::Hole()};
[[maybe_unused]] alignas(EAS) FrameType type {0};
@ -594,6 +598,11 @@ struct InterpretedFrameBase : public base::AlignedStruct<base::AlignedPointer::S
return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
}
static constexpr size_t GetSize(bool isArch32)
{
return isArch32 ? InterpretedFrameBase::SizeArch32 : InterpretedFrameBase::SizeArch64;
}
alignas(EAS) JSTaggedType *prev {nullptr}; // for llvm :c-fp ; for interrupt: thread-fp for gc
alignas(EAS) FrameType type {FrameType::OPTIMIZED_FRAME}; // 0
};
@ -867,6 +876,11 @@ struct AsmInterpretedEntryFrame : public base::AlignedStruct<JSTaggedValue::Tagg
return base.prev;
}
static size_t GetBaseOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32);
}
static AsmInterpretedEntryFrame* GetFrameFromSp(const JSTaggedType *sp)
{
return reinterpret_cast<AsmInterpretedEntryFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
@ -876,7 +890,7 @@ struct AsmInterpretedEntryFrame : public base::AlignedStruct<JSTaggedValue::Tagg
alignas(EAS) InterpretedFrameBase base;
};
struct AsmInterpretedBridgeFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
struct AsmInterpretedBridgeFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
AsmInterpretedEntryFrame,
base::AlignedPointer> {
enum class Index : size_t {
@ -900,7 +914,17 @@ struct AsmInterpretedBridgeFrame : public base::AlignedStruct<JSTaggedValue::Tag
return entry.base.prev;
}
alignas(EAS) AsmInterpretedEntryFrame entry;
static size_t GetReturnAddrOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
}
static constexpr size_t GetSize(bool isArch32)
{
return isArch32 ? AsmInterpretedBridgeFrame::SizeArch32 : AsmInterpretedBridgeFrame::SizeArch64;
}
AsmInterpretedEntryFrame entry;
alignas(EAS) uintptr_t returnAddr;
uintptr_t GetReturnAddr() const
{
@ -1170,6 +1194,10 @@ public:
{
return current_;
}
void GetCalleeRegAndOffsetVec(kungfu::CalleeRegAndOffsetVec &ret) const
{
ret = calleeRegInfo_;
}
int ComputeDelta() const;
template <GCVisitedFlag GCVisit = GCVisitedFlag::IGNORED>
void Advance();
@ -1189,7 +1217,8 @@ public:
}
bool IteratorStackMap(const RootVisitor &visitor, const RootBaseAndDerivedVisitor &derivedVisitor) const;
void CollectBCOffsetInfo(kungfu::ConstInfo &info) const;
std::tuple<uint64_t, uint8_t *, int> CalCallSiteInfo(uintptr_t retAddr) const;
void CollectArkDeopt(std::vector<kungfu::ARKDeopt>& deopts) const;
std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> CalCallSiteInfo(uintptr_t retAddr) const;
int GetCallSiteDelta(uintptr_t retAddr) const;
private:
JSTaggedType *current_ {nullptr};
@ -1199,6 +1228,7 @@ private:
uintptr_t optimizedReturnAddr_ {0};
uint8_t *stackMapAddr_ {nullptr};
int fpDeltaPrevFrameSp_ {0};
kungfu::CalleeRegAndOffsetVec calleeRegInfo_;
};
} // namespace panda::ecmascript
extern "C" int step_ark_managed_native_frame(

View File

@ -7173,6 +7173,23 @@ bool EcmaInterpreter::IsFastNewFrameEnter(JSFunction *ctor, JSHandle<Method> met
return false;
}
JSTaggedType *EcmaInterpreter::GetInterpreterFrameEnd(JSThread *thread, JSTaggedType *sp)
{
JSTaggedType *newSp;
if (thread->IsAsmInterpreter()) {
newSp = sp - InterpretedEntryFrame::NumOfMembers();
} else {
if (FrameHandler::GetFrameType(sp) == FrameType::INTERPRETER_FRAME ||
FrameHandler::GetFrameType(sp) == FrameType::INTERPRETER_FAST_NEW_FRAME) {
newSp = sp - InterpretedFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
} else {
newSp =
sp - InterpretedEntryFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
}
return newSp;
}
bool EcmaInterpreter::IsFastNewFrameExit(JSTaggedType *sp)
{
return GET_FRAME(sp)->base.type == FrameType::INTERPRETER_FAST_NEW_FRAME;

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/frames.h"
#include "ecmascript/interpreter/frame_handler.h"
@ -40,20 +40,8 @@ EcmaRuntimeCallInfo* EcmaInterpreter::NewRuntimeCallInfo(
JSThread *thread, JSHandle<JSTaggedValue> func, JSHandle<JSTaggedValue> thisObj, JSHandle<JSTaggedValue> newTarget,
uint32_t numArgs, bool needCheckStack)
{
JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
JSTaggedType *newSp = nullptr;
JSTaggedType *prevSp = sp;
if (thread->IsAsmInterpreter()) {
newSp = sp - InterpretedEntryFrame::NumOfMembers();
} else {
if (FrameHandler::GetFrameType(sp) == FrameType::INTERPRETER_FRAME ||
FrameHandler::GetFrameType(sp) == FrameType::INTERPRETER_FAST_NEW_FRAME) {
newSp = sp - InterpretedFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
} else {
newSp =
sp - InterpretedEntryFrame::NumOfMembers(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
}
JSTaggedType *prevSp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
JSTaggedType *newSp = GetInterpreterFrameEnd(thread, prevSp);
if (needCheckStack && UNLIKELY(thread->DoStackOverflowCheck(newSp - numArgs - NUM_MANDATORY_JSFUNC_ARGS))) {
return nullptr;
}

View File

@ -63,6 +63,9 @@ public:
static inline bool IsFastNewFrameEnter(JSFunction *ctor, JSHandle<Method> method);
static inline bool IsFastNewFrameExit(JSTaggedType *sp);
static inline int16_t GetHotnessCounter(uint32_t codeSize);
static inline JSTaggedType *GetInterpreterFrameEnd(JSThread *thread, JSTaggedType *sp);
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_INTERPRETER_INTERPRETER_H

View File

@ -77,6 +77,8 @@ public:
static constexpr JSTaggedType TAG_MARK = 0xFFFFULL << TAG_BITS_SHIFT;
// int tag
static constexpr JSTaggedType TAG_INT = TAG_MARK;
static constexpr JSTaggedType TAG_INT32_INC_MAX = INT32_MAX + 1ULL;
static constexpr JSTaggedType TAG_INT32_DEC_MIN = INT32_MIN - 1ULL;
// object tag
static constexpr JSTaggedType TAG_OBJECT = 0x0000ULL << TAG_BITS_SHIFT;
// weak object tag

View File

@ -432,9 +432,10 @@ size_t JSThread::GetAsmStackLimit()
}
uintptr_t threadStackStart = threadStackLimit + size;
LOG_ECMA(INFO) << "Current thread stack start:" << threadStackStart
<< " Used stack before js stack start:" << (threadStackStart - GetCurrentStackPosition())
<< " Current thread asm stack limit:" << result;
LOG_INTERPRETER(INFO) << "Current thread stack start: " << reinterpret_cast<void *>(threadStackStart);
LOG_INTERPRETER(INFO) << "Used stack before js stack start: "
<< reinterpret_cast<void *>(threadStackStart - GetCurrentStackPosition());
LOG_INTERPRETER(INFO) << "Current thread asm stack limit: " << reinterpret_cast<void *>(result);
ret = pthread_attr_destroy(&attr);
if (ret != 0) {
LOG_ECMA(ERROR) << "Destroy current thread attr failed";

View File

@ -68,6 +68,11 @@ public:
return pf_;
}
std::string GetFileName() const
{
return pf_->GetFilename();
}
MethodLiteral* GetMethodLiterals() const
{
return methodLiterals_;

View File

@ -114,6 +114,11 @@ public:
HaveNewTargetWithCallField() + HaveThisWithCallField();
}
uint32_t GetNumberVRegs() const
{
return GetNumVregsWithCallField() + GetNumArgs();
}
static uint64_t SetNumArgsWithCallField(uint64_t callField, uint32_t numargs)
{
return NumArgsBits::Update(callField, numargs);
@ -179,6 +184,11 @@ public:
return NumVregsBits::Decode(callField);
}
uint32_t GetNumVregsWithCallField() const
{
return NumVregsBits::Decode(callField_);
}
static uint32_t GetNumArgsWithCallField(uint64_t callField)
{
return NumArgsBits::Decode(callField);

View File

@ -98,14 +98,14 @@ void Heap::Initialize()
maxMarkTaskCount_ = std::min<size_t>(ecmaVm_->GetJSOptions().GetGcThreadNum(),
maxEvacuateTaskCount_ - 1);
LOG_GC(INFO) << "heap initialize: heap size = " << maxHeapSize
<< ", semispace capacity = " << minSemiSpaceCapacity
<< ", nonmovablespace capacity = " << nonmovableSpaceCapacity
<< ", snapshotspace capacity = " << snapshotSpaceCapacity
<< ", machinecodespace capacity = " << machineCodeSpaceCapacity
<< ", oldspace capacity = " << oldSpaceCapacity
<< ", globallimit = " << globalSpaceAllocLimit_
<< ", gcThreadNum = " << maxMarkTaskCount_;
LOG_GC(INFO) << "heap initialize: heap size = " << (maxHeapSize / 1_MB) << "MB"
<< ", semispace capacity = " << (minSemiSpaceCapacity / 1_MB) << "MB"
<< ", nonmovablespace capacity = " << (nonmovableSpaceCapacity / 1_MB) << "MB"
<< ", snapshotspace capacity = " << (snapshotSpaceCapacity / 1_MB) << "MB"
<< ", machinecodespace capacity = " << (machineCodeSpaceCapacity / 1_MB) << "MB"
<< ", oldspace capacity = " << (oldSpaceCapacity / 1_MB) << "MB"
<< ", globallimit = " << (globalSpaceAllocLimit_ / 1_MB) << "MB"
<< ", gcThreadNum = " << maxMarkTaskCount_;
parallelGC_ = ecmaVm_->GetJSOptions().EnableParallelGC();
bool concurrentMarkerEnabled = ecmaVm_->GetJSOptions().EnableConcurrentMark();
markType_ = MarkType::MARK_YOUNG;

View File

@ -19,7 +19,6 @@
#include "ecmascript/jspandafile/program_object.h"
namespace panda::ecmascript {
// It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods.
std::string Method::ParseFunctionName() const
{
const JSPandaFile *jsPandaFile = GetJSPandaFile();
@ -32,6 +31,11 @@ const char *Method::GetMethodName() const
return MethodLiteral::GetMethodName(jsPandaFile, GetMethodId());
}
const char *Method::GetMethodName(const JSPandaFile* file) const
{
return MethodLiteral::GetMethodName(file, GetMethodId());
}
uint32_t Method::GetCodeSize() const
{
const JSPandaFile *jsPandaFile = GetJSPandaFile();

View File

@ -126,6 +126,11 @@ public:
HaveNewTargetWithCallField() + HaveThisWithCallField();
}
uint32_t GetNumberVRegs() const
{
return GetNumVregsWithCallField() + GetNumArgs();
}
inline int16_t GetHotnessCounter() const
{
uint64_t literalInfo = GetLiteralInfo();
@ -224,6 +229,7 @@ public:
MethodLiteral *GetMethodLiteral() const;
const char *PUBLIC_API GetMethodName() const;
const char *PUBLIC_API GetMethodName(const JSPandaFile* file) const;
std::string PUBLIC_API ParseFunctionName() const;
static constexpr size_t CONSTANT_POOL_OFFSET = TaggedObjectSize();

View File

@ -20,6 +20,7 @@
#include "ecmascript/compiler/call_signature.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/deoptimizer.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/frames.h"
@ -2147,6 +2148,18 @@ JSTaggedValue RuntimeStubs::CallBoundFunction(EcmaRuntimeCallInfo *info)
return EcmaInterpreter::Execute(runtimeInfo);
}
DEF_RUNTIME_STUBS(DeoptHandler)
{
RUNTIME_STUBS_HEADER(DeoptHandler);
Deoptimizier deopt(thread);
std::vector<kungfu::ARKDeopt> deoptBundle;
deopt.CollectDeoptBundleVec(deoptBundle);
ASSERT(!deoptBundle.empty());
deopt.CollectVregs(deoptBundle);
return deopt.ConstructAsmInterpretFrame();
}
void RuntimeStubs::Initialize(JSThread *thread)
{
#define DEF_RUNTIME_STUB(name) kungfu::RuntimeStubCSigns::ID_##name

View File

@ -78,7 +78,8 @@ using JSFunctionEntryType = JSTaggedValue (*)(uintptr_t glue, uintptr_t prevFp,
V(JSCallWithArgV) \
V(ConstructorJSCallWithArgV) \
V(JSProxyCallInternalWithArgV) \
V(OptimizedCallOptimized)
V(OptimizedCallOptimized) \
V(DeoptHandlerAsm)
#define RUNTIME_STUB_WITHOUT_GC_LIST(V) \
@ -93,7 +94,7 @@ using JSFunctionEntryType = JSTaggedValue (*)(uintptr_t glue, uintptr_t prevFp,
V(FindElementWithCache) \
V(CreateArrayFromList) \
V(StringsAreEquals) \
V(BigIntEquals) \
V(BigIntEquals)
#define RUNTIME_STUB_WITH_GC_LIST(V) \
V(AddElementInternal) \
@ -279,7 +280,8 @@ using JSFunctionEntryType = JSTaggedValue (*)(uintptr_t glue, uintptr_t prevFp,
V(StringEqual) \
V(LdPatchVar) \
V(StPatchVar) \
V(LdObjByName)
V(LdObjByName) \
V(DeoptHandler)
#define RUNTIME_STUB_LIST(V) \
RUNTIME_ASM_STUB_LIST(V) \

View File

@ -44,6 +44,7 @@ enum class TSPrimitiveType : int {
UNDEFINED,
INT,
BIG_INT,
DOUBLE,
END
};

View File

@ -480,8 +480,7 @@ JSHandle<JSTaggedValue> TSManager::GetTSType(const GlobalTSTypeRef &gt) const
std::string TSManager::GetTypeStr(kungfu::GateType gateType) const
{
ASSERT(gateType.IsTSType());
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
auto typeKind = GetTypeKind(gt);
switch (typeKind) {
case TSTypeKind::PRIMITIVE:
@ -531,6 +530,8 @@ std::string TSManager::GetPrimitiveStr(const GlobalTSTypeRef &gt) const
return "undefined";
case TSPrimitiveType::INT:
return "int";
case TSPrimitiveType::DOUBLE:
return "double";
case TSPrimitiveType::BIG_INT:
return "bigint";
default:

View File

@ -148,7 +148,7 @@ public:
inline GlobalTSTypeRef PUBLIC_API GetPropType(kungfu::GateType gateType, JSHandle<EcmaString> propertyName) const
{
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
return GetPropType(gt, propertyName);
}
@ -157,13 +157,13 @@ public:
// use for object
inline GlobalTSTypeRef PUBLIC_API GetPropType(kungfu::GateType gateType, const uint64_t key) const
{
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
return GetPropType(gt, key);
}
inline GlobalTSTypeRef PUBLIC_API CreateClassInstanceType(kungfu::GateType gateType)
{
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
return CreateClassInstanceType(gt);
}
@ -187,7 +187,7 @@ public:
inline GlobalTSTypeRef PUBLIC_API GetFuncReturnValueTypeGT(kungfu::GateType gateType) const
{
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
return GetFuncReturnValueTypeGT(gt);
}
@ -195,7 +195,7 @@ public:
inline GlobalTSTypeRef PUBLIC_API GetArrayParameterTypeGT(kungfu::GateType gateType) const
{
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType());
GlobalTSTypeRef gt = gateType.GetGTRef();
return GetArrayParameterTypeGT(gt);
}
@ -289,7 +289,7 @@ public:
#define IS_TSTYPEKIND(NAME, TSTYPEKIND) \
bool inline PUBLIC_API Is##NAME##TypeKind(const kungfu::GateType &gateType) const \
{ \
GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.GetType()); \
GlobalTSTypeRef gt = gateType.GetGTRef(); \
return GetTypeKind(gt) == (TSTYPEKIND); \
}

View File

@ -127,7 +127,8 @@ group("ark_aot_test") {
"supercallspread:supercallspreadAotAction",
"suspendgenerator:suspendgeneratorAotAction",
"suspendgeneratorbranch:suspendgeneratorbranchAotAction",
"suspendgeneratorfor:suspendgeneratorforAotAction",
# "suspendgeneratorfor:suspendgeneratorforAotAction",
"suspendgeneratorphi:suspendgeneratorphiAotAction",
"suspendgeneratorreturn:suspendgeneratorreturnAotAction",
"suspendgeneratorthrow:suspendgeneratorthrowAotAction",

View File

@ -19,6 +19,7 @@ let b:number = 2;
let c:number = a / b;
print(c);
function foo(arg0:number, arg1:number) {
print(arg0 / arg1);
}
@ -37,4 +38,4 @@ function foo2(arg:number) {
}
return arg;
}
print(foo2(3));
print(foo2(3));

View File

@ -23,4 +23,3 @@ function foo() {
}
}
foo();

View File

@ -18,7 +18,7 @@ declare function AssertType(value:any, type:string):void;
let num1 : number = 1;
let num2 : number = 2;
let ans1 = num1 + num2;
AssertType(ans1, "number");
AssertType(ans1, "int");
let arr1 : number[] = [1, 2];
let arr2 : number[] = [1, 2];
@ -37,4 +37,43 @@ declare function AssertType(value:any, type:string):void;
let ans5 = arr1[0] + arr3[0];
AssertType(ans5, "string");
let double1 : number = 0.1;
let double2 : number = 0.2;
let double3 : number = 0.8;
let ans6 = double1 + double2;
let ans7 = double2 + double3;
AssertType(ans6, "double");
AssertType(ans7, "double");
let ans8 = double1 + num1;
AssertType(ans8, "double");
let ans9 = num1 + double1;
AssertType(ans9, "double");
let inf1 : number = Infinity;
let nan1 : number = NaN;
let ans10 = inf1 + inf1;
let ans11 = inf1 + nan1;
let ans12 = nan1 + inf1;
let ans13 = num1 + inf1;
let ans14 = inf1 + num1;
let ans15 = num1 + nan1;
let ans16 = nan1 + num1;
let ans17 = double1 + inf1;
let ans18 = inf1 + double1;
let ans19 = double1 + nan1;
let ans20 = nan1 + double1;
AssertType(ans10, "number");
AssertType(ans11, "number");
AssertType(ans12, "number");
AssertType(ans13, "number");
AssertType(ans14, "number");
AssertType(ans15, "number");
AssertType(ans16, "number");
AssertType(ans17, "number");
AssertType(ans18, "number");
AssertType(ans19, "number");
AssertType(ans20, "number");
}

View File

@ -17,6 +17,48 @@ declare function AssertType(value:any, type:string):void;
{
let num1 : number = 1;
let num2 : number = 2;
let ans = num1 / num2;
AssertType(ans, "number");
let ans1 = num1 / num2;
AssertType(ans1, "double");
let double1 : number = 1.5;
let double2 : number = 0.5;
let ans2 = num1 / double1;
let ans3 = double1 / num1;
let ans4 = double1 / double2;
let ans5 = double2 / double1;
AssertType(ans2, "double");
AssertType(ans3, "double");
AssertType(ans4, "double");
AssertType(ans5, "double");
let zero1 : number = 0;
let ans6 = num1 / zero1;
let ans7 = double1 / zero1;
AssertType(ans6, "double");
AssertType(ans7, "double");
let inf1 : number = Infinity;
let nan1 : number = NaN;
let ans8 = inf1 / inf1;
let ans9 = inf1 / nan1;
let ans10 = nan1 / inf1;
let ans11 = num1 / inf1;
let ans12 = inf1 / num1;
let ans13 = num1 / nan1;
let ans14 = nan1 / num1;
let ans15 = double1 / inf1;
let ans16 = inf1 / double1;
let ans17 = double1 / nan1;
let ans18 = nan1 / double1;
AssertType(ans8, "number");
AssertType(ans9, "number");
AssertType(ans10, "number");
AssertType(ans11, "number");
AssertType(ans12, "number");
AssertType(ans13, "number");
AssertType(ans14, "number");
AssertType(ans15, "number");
AssertType(ans16, "number");
AssertType(ans17, "number");
AssertType(ans18, "number");
}

View File

@ -19,4 +19,4 @@ num1 = 2;
num1 = 3;
num1 =10;
var ans = num1;
AssertType(ans, "number");
AssertType(ans, "int");

View File

@ -23,15 +23,15 @@ declare function AssertType(value:any, type:string):void;
let c = a + b;
let d = b + 2;
let r = s + t;
AssertType(r, "number");
AssertType(r, "int");
function g():any {
AssertType(c, "string");
AssertType(d, "number");
AssertType(d, "int");
AssertType(c + d, "string");
AssertType(r, "number");
AssertType(r, "int");
return c + d;
}
return g();
}
AssertType(s + t, "number");
AssertType(s + t, "int");
}

Some files were not shown because too many files have changed in this diff Show More