2022-10-03 02:45:22 +00:00
|
|
|
/*
|
2022-10-13 14:00:46 +00:00
|
|
|
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
2022-10-03 02:45:22 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-11-25 08:51:55 +00:00
|
|
|
#ifndef ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H
|
|
|
|
#define ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H
|
|
|
|
|
2022-10-03 02:45:22 +00:00
|
|
|
#include "ecmascript/base/aligned_struct.h"
|
2022-10-15 04:09:38 +00:00
|
|
|
#include "ecmascript/compiler/argument_accessor.h"
|
2022-11-25 06:44:53 +00:00
|
|
|
#include "ecmascript/deoptimizer/calleeReg.h"
|
2022-10-03 02:45:22 +00:00
|
|
|
#include "ecmascript/js_handle.h"
|
|
|
|
#include "ecmascript/js_tagged_value.h"
|
2022-11-28 04:30:50 +00:00
|
|
|
#include "ecmascript/stackmap/llvm_stackmap_type.h"
|
2022-10-03 02:45:22 +00:00
|
|
|
|
|
|
|
namespace panda::ecmascript {
|
|
|
|
class JSThread;
|
|
|
|
enum class SpecVregIndex: int {
|
2023-03-08 07:37:47 +00:00
|
|
|
PC_OFFSET_INDEX = -1,
|
2022-10-03 02:45:22 +00:00
|
|
|
ACC_INDEX = -2,
|
2023-03-08 07:37:47 +00:00
|
|
|
ENV_INDEX = -3,
|
2023-03-27 09:23:59 +00:00
|
|
|
FUNC_INDEX = -4,
|
|
|
|
NEWTARGET_INDEX = -5,
|
|
|
|
THIS_OBJECT_INDEX = -6,
|
2023-05-18 11:13:51 +00:00
|
|
|
ACTUAL_ARGC_INDEX = -7,
|
2022-10-03 02:45:22 +00:00
|
|
|
};
|
|
|
|
|
2022-10-13 14:00:46 +00:00
|
|
|
struct Context {
|
2022-10-03 02:45:22 +00:00
|
|
|
uintptr_t callsiteSp;
|
|
|
|
uintptr_t callsiteFp;
|
|
|
|
kungfu::CalleeRegAndOffsetVec calleeRegAndOffset;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(),
|
2022-10-10 08:13:57 +00:00
|
|
|
base::AlignedPointer,
|
2022-10-03 02:45:22 +00:00
|
|
|
base::AlignedPointer,
|
|
|
|
base::AlignedPointer,
|
|
|
|
base::AlignedPointer> {
|
|
|
|
enum class Index : size_t {
|
2023-05-10 13:22:15 +00:00
|
|
|
INLINE_DEPTH_INDEX = 0,
|
2022-10-13 14:00:46 +00:00
|
|
|
CALLFRAME_TOP_INDEX,
|
|
|
|
RETURN_ADDRESS_INDEX,
|
|
|
|
CALLERFRAME_POINTER_INDEX,
|
|
|
|
NUM_OF_MEMBER
|
2022-10-03 02:45:22 +00:00
|
|
|
};
|
|
|
|
|
2022-10-13 14:00:46 +00:00
|
|
|
static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes);
|
2022-10-03 02:45:22 +00:00
|
|
|
|
2023-05-10 13:22:15 +00:00
|
|
|
static size_t GetInlineDepthOffset(bool isArch32)
|
2022-10-03 02:45:22 +00:00
|
|
|
{
|
2023-05-10 13:22:15 +00:00
|
|
|
return GetOffset<static_cast<size_t>(Index::INLINE_DEPTH_INDEX)>(isArch32);
|
2022-10-03 02:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t GetCallFrameTopOffset(bool isArch32)
|
|
|
|
{
|
2022-10-13 14:00:46 +00:00
|
|
|
return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32);
|
2022-10-03 02:45:22 +00:00
|
|
|
}
|
|
|
|
|
2022-10-10 08:13:57 +00:00
|
|
|
static size_t GetReturnAddressOffset(bool isArch32)
|
|
|
|
{
|
2022-10-13 14:00:46 +00:00
|
|
|
return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32);
|
2022-10-10 08:13:57 +00:00
|
|
|
}
|
|
|
|
|
2022-10-03 02:45:22 +00:00
|
|
|
static size_t GetCallerFpOffset(bool isArch32)
|
|
|
|
{
|
2022-10-13 14:00:46 +00:00
|
|
|
return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32);
|
2022-10-03 02:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr size_t GetSize(bool isArch32)
|
|
|
|
{
|
|
|
|
return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64;
|
|
|
|
}
|
|
|
|
|
2023-05-10 13:22:15 +00:00
|
|
|
alignas(EAS) size_t inlineDepth_ {0};
|
2022-10-03 02:45:22 +00:00
|
|
|
alignas(EAS) uintptr_t callFrameTop_{0};
|
2022-10-10 08:13:57 +00:00
|
|
|
alignas(EAS) uintptr_t returnAddr_{0};
|
2022-10-03 02:45:22 +00:00
|
|
|
alignas(EAS) uintptr_t callerFp_{0};
|
|
|
|
// out put data
|
|
|
|
};
|
|
|
|
|
2022-10-15 04:09:38 +00:00
|
|
|
class FrameWriter;
|
2022-10-19 02:21:31 +00:00
|
|
|
class Deoptimizier {
|
2022-10-03 02:45:22 +00:00
|
|
|
public:
|
2023-03-20 01:26:31 +00:00
|
|
|
using ARKDeopt = kungfu::ARKDeopt;
|
|
|
|
using CalleeReg = kungfu::CalleeReg;
|
|
|
|
using CalleeRegAndOffsetVec = kungfu::CalleeRegAndOffsetVec;
|
|
|
|
using CommonArgIdx = kungfu::CommonArgIdx;
|
|
|
|
using DeoptType = kungfu::DeoptType;
|
|
|
|
using DwarfRegType = kungfu::LLVMStackMapType::DwarfRegType;
|
|
|
|
using DwarfRegAndOffsetType = kungfu::LLVMStackMapType::DwarfRegAndOffsetType;
|
|
|
|
using IntType = kungfu::LLVMStackMapType::IntType;
|
|
|
|
using LargeInt = kungfu::LLVMStackMapType::LargeInt;
|
|
|
|
using LocationTy = kungfu::LocationTy;
|
|
|
|
using OffsetType = kungfu::LLVMStackMapType::OffsetType;
|
|
|
|
using VRegId = kungfu::LLVMStackMapType::VRegId;
|
|
|
|
|
2023-05-10 13:22:15 +00:00
|
|
|
explicit Deoptimizier(JSThread *thread, size_t depth) : thread_(thread), inlineDepth_(depth)
|
2022-10-19 02:21:31 +00:00
|
|
|
{
|
2023-03-20 01:26:31 +00:00
|
|
|
CalleeReg callreg;
|
2022-10-19 02:21:31 +00:00
|
|
|
numCalleeRegs_ = static_cast<size_t>(callreg.GetCallRegNum());
|
2022-11-25 06:44:53 +00:00
|
|
|
JSRuntimeOptions options = thread_->GetEcmaVM()->GetJSOptions();
|
2022-11-28 08:16:35 +00:00
|
|
|
traceDeopt_ = options.GetTraceDeopt();
|
2022-10-03 02:45:22 +00:00
|
|
|
}
|
2023-05-10 13:22:15 +00:00
|
|
|
void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift);
|
|
|
|
void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle);
|
|
|
|
JSTaggedType ConstructAsmInterpretFrame();
|
|
|
|
void UpdateAndDumpDeoptInfo(kungfu::DeoptType type);
|
|
|
|
static std::string DisplayItems(kungfu::DeoptType type);
|
|
|
|
static int32_t EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift);
|
|
|
|
static size_t ComputeShift(size_t depth);
|
|
|
|
static int32_t DecodeVregIndex(OffsetType id, size_t shift);
|
|
|
|
static size_t DecodeDeoptDepth(OffsetType id, size_t shift);
|
2022-10-13 14:00:46 +00:00
|
|
|
JSThread *GetThread() const
|
|
|
|
{
|
2022-10-03 02:45:22 +00:00
|
|
|
return thread_;
|
|
|
|
}
|
|
|
|
|
2023-03-17 07:02:11 +00:00
|
|
|
static const char *GetLLVMDeoptRelocateSymbol()
|
|
|
|
{
|
|
|
|
return "__llvm_deoptimize";
|
|
|
|
}
|
|
|
|
|
2022-10-03 02:45:22 +00:00
|
|
|
private:
|
2023-03-20 01:26:31 +00:00
|
|
|
size_t GetFrameIndex(CommonArgIdx index)
|
2022-10-15 04:09:38 +00:00
|
|
|
{
|
2023-03-20 01:26:31 +00:00
|
|
|
return static_cast<size_t>(index) - static_cast<size_t>(CommonArgIdx::FUNC);
|
2022-10-15 04:09:38 +00:00
|
|
|
}
|
|
|
|
JSTaggedValue GetFrameArgv(size_t idx)
|
|
|
|
{
|
|
|
|
ASSERT(frameArgvs_ != nullptr);
|
|
|
|
ASSERT(idx < frameArgc_);
|
|
|
|
return JSTaggedValue(frameArgvs_[idx]);
|
|
|
|
}
|
2023-03-20 01:26:31 +00:00
|
|
|
JSTaggedValue GetFrameArgv(CommonArgIdx index)
|
2022-10-15 04:09:38 +00:00
|
|
|
{
|
|
|
|
return GetFrameArgv(GetFrameIndex(index));
|
|
|
|
}
|
|
|
|
JSTaggedValue GetActualFrameArgs(int32_t index)
|
|
|
|
{
|
|
|
|
index += NUM_MANDATORY_JSFUNC_ARGS;
|
|
|
|
return GetFrameArgv(static_cast<size_t>(index));
|
|
|
|
}
|
2023-05-10 13:22:15 +00:00
|
|
|
bool CollectVirtualRegisters(Method* method, FrameWriter *frameWriter, size_t curDepth);
|
|
|
|
bool HasDeoptValue(size_t curDepth, int32_t index) const
|
2022-10-15 04:09:38 +00:00
|
|
|
{
|
2023-05-10 13:22:15 +00:00
|
|
|
ASSERT(curDepth <= inlineDepth_);
|
|
|
|
return deoptVregs_.find({curDepth, static_cast<OffsetType>(index)}) != deoptVregs_.end();
|
2022-10-15 04:09:38 +00:00
|
|
|
}
|
2023-05-10 13:22:15 +00:00
|
|
|
JSTaggedValue GetDeoptValue(size_t curDepth, int32_t index) const
|
2022-11-09 02:05:55 +00:00
|
|
|
{
|
2023-05-10 13:22:15 +00:00
|
|
|
ASSERT(curDepth <= inlineDepth_);
|
|
|
|
if (!HasDeoptValue(curDepth, index)) {
|
2022-11-09 02:05:55 +00:00
|
|
|
return JSTaggedValue::Undefined();
|
|
|
|
}
|
2023-05-10 13:22:15 +00:00
|
|
|
return deoptVregs_.at({curDepth, static_cast<OffsetType>(index)});
|
2022-11-09 02:05:55 +00:00
|
|
|
}
|
2022-10-03 02:45:22 +00:00
|
|
|
Method* GetMethod(JSTaggedValue &target);
|
|
|
|
void RelocateCalleeSave();
|
2023-05-10 13:22:15 +00:00
|
|
|
void Dump(Method* method, kungfu::DeoptType type, size_t depth);
|
|
|
|
size_t GetCallSize(size_t curDepth, const uint8_t *resumePc);
|
2022-10-03 02:45:22 +00:00
|
|
|
JSThread *thread_ {nullptr};
|
|
|
|
uintptr_t *calleeRegAddr_ {nullptr};
|
|
|
|
size_t numCalleeRegs_ {0};
|
|
|
|
AsmStackContext stackContext_;
|
|
|
|
|
2023-05-10 13:22:15 +00:00
|
|
|
std::map<std::pair<size_t, OffsetType>, JSTaggedValue> deoptVregs_;
|
2022-10-15 04:09:38 +00:00
|
|
|
struct Context context_ {0, 0, {}};
|
2023-05-10 13:22:15 +00:00
|
|
|
std::unordered_map<size_t, size_t> pc_;
|
|
|
|
std::unordered_map<size_t, size_t> jumpSize_;
|
2022-10-15 04:09:38 +00:00
|
|
|
size_t frameArgc_ {0};
|
|
|
|
JSTaggedType *frameArgvs_ {nullptr};
|
2022-11-25 08:51:55 +00:00
|
|
|
bool traceDeopt_{false};
|
2023-05-10 13:22:15 +00:00
|
|
|
size_t inlineDepth_ {0};
|
2022-10-03 02:45:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace panda::ecmascript
|
2022-11-25 08:51:55 +00:00
|
|
|
#endif // ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H
|