mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
commit
ceba8e7e70
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
75
ecmascript/calleeReg.cpp
Normal 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
70
ecmascript/calleeReg.h
Normal 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
|
@ -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",
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_);
|
||||
|
@ -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
|
||||
|
@ -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 ¤tPhi);
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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*>( \
|
||||
|
@ -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()
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
131
ecmascript/compiler/frame_states.cpp
Normal file
131
ecmascript/compiler/frame_states.cpp
Normal 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_;
|
||||
}
|
||||
}
|
||||
}
|
133
ecmascript/compiler/frame_states.h
Normal file
133
ecmascript/compiler/frame_states.h
Normal 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
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
149
ecmascript/compiler/guard_eliminating.cpp
Normal file
149
ecmascript/compiler/guard_eliminating.cpp
Normal 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
|
53
ecmascript/compiler/guard_eliminating.h
Normal file
53
ecmascript/compiler/guard_eliminating.h
Normal 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
|
62
ecmascript/compiler/guard_lowering.cpp
Normal file
62
ecmascript/compiler/guard_lowering.cpp
Normal 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
|
55
ecmascript/compiler/guard_lowering.h
Normal file
55
ecmascript/compiler/guard_lowering.h
Normal 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
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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, ¬Number);
|
||||
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(¬Number);
|
||||
{
|
||||
// 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, ¬Number);
|
||||
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(¬Number);
|
||||
{
|
||||
// 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, ¬Primitive);
|
||||
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(¬Primitive);
|
||||
{
|
||||
// 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
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
225
ecmascript/deoptimizer.cpp
Normal 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
127
ecmascript/deoptimizer.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -68,6 +68,11 @@ public:
|
||||
return pf_;
|
||||
}
|
||||
|
||||
std::string GetFileName() const
|
||||
{
|
||||
return pf_->GetFilename();
|
||||
}
|
||||
|
||||
MethodLiteral* GetMethodLiterals() const
|
||||
{
|
||||
return methodLiterals_;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -44,6 +44,7 @@ enum class TSPrimitiveType : int {
|
||||
UNDEFINED,
|
||||
INT,
|
||||
BIG_INT,
|
||||
DOUBLE,
|
||||
END
|
||||
};
|
||||
|
||||
|
@ -480,8 +480,7 @@ JSHandle<JSTaggedValue> TSManager::GetTSType(const GlobalTSTypeRef >) 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 >) const
|
||||
return "undefined";
|
||||
case TSPrimitiveType::INT:
|
||||
return "int";
|
||||
case TSPrimitiveType::DOUBLE:
|
||||
return "double";
|
||||
case TSPrimitiveType::BIG_INT:
|
||||
return "bigint";
|
||||
default:
|
||||
|
@ -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); \
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,8 @@ group("ark_aot_test") {
|
||||
"supercallspread:supercallspreadAotAction",
|
||||
"suspendgenerator:suspendgeneratorAotAction",
|
||||
"suspendgeneratorbranch:suspendgeneratorbranchAotAction",
|
||||
"suspendgeneratorfor:suspendgeneratorforAotAction",
|
||||
|
||||
# "suspendgeneratorfor:suspendgeneratorforAotAction",
|
||||
"suspendgeneratorphi:suspendgeneratorphiAotAction",
|
||||
"suspendgeneratorreturn:suspendgeneratorreturnAotAction",
|
||||
"suspendgeneratorthrow:suspendgeneratorthrowAotAction",
|
||||
|
@ -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));
|
||||
|
@ -23,4 +23,3 @@ function foo() {
|
||||
}
|
||||
}
|
||||
foo();
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -19,4 +19,4 @@ num1 = 2;
|
||||
num1 = 3;
|
||||
num1 =10;
|
||||
var ans = num1;
|
||||
AssertType(ans, "number");
|
||||
AssertType(ans, "int");
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user