• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H
17 #define ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H
18 
19 #include "ecmascript/base/aligned_struct.h"
20 #include "ecmascript/compiler/argument_accessor.h"
21 #include "ecmascript/deoptimizer/calleeReg.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/stackmap/llvm/llvm_stackmap_type.h"
26 
27 namespace panda::ecmascript {
28 class JSThread;
29 enum class SpecVregIndex: int {
30     PC_OFFSET_INDEX = -1,
31     ACC_INDEX = -2,
32     ENV_INDEX = -3,
33     FUNC_INDEX = -4,
34     NEWTARGET_INDEX = -5,
35     THIS_OBJECT_INDEX = -6,
36     ACTUAL_ARGC_INDEX = -7,
37     FIRST_METHOD_OFFSET_INDEX = -8,
38     PADDING1 = -9,
39     PADDING2 = -10,
40     PADDING3 = -11,
41     MAX_METHOD_OFFSET_INDEX = -12,
42 };
43 
44 static constexpr uint32_t MAX_METHOD_OFFSET_NUM = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) -
45                                                   static_cast<int32_t>(SpecVregIndex::MAX_METHOD_OFFSET_INDEX) + 1;
46 
47 struct Context {
48     uintptr_t callsiteSp;
49     uintptr_t callsiteFp;
50     kungfu::CalleeRegAndOffsetVec calleeRegAndOffset;
51 };
52 
53 struct AsmStackContext : public base::AlignedStruct<base::AlignedPointer::Size(),
54                                                     base::AlignedPointer,
55                                                     base::AlignedPointer,
56                                                     base::AlignedPointer,
57                                                     base::AlignedPointer> {
58     enum class Index : size_t {
59         INLINE_DEPTH_INDEX = 0,
60         CALLFRAME_TOP_INDEX,
61         RETURN_ADDRESS_INDEX,
62         CALLERFRAME_POINTER_INDEX,
63         NUM_OF_MEMBER
64     };
65 
66     static_assert(static_cast<size_t>(Index::NUM_OF_MEMBER) == NumOfTypes);
67 
GetInlineDepthOffsetAsmStackContext68     static size_t GetInlineDepthOffset(bool isArch32)
69     {
70         return GetOffset<static_cast<size_t>(Index::INLINE_DEPTH_INDEX)>(isArch32);
71     }
72 
GetCallFrameTopOffsetAsmStackContext73     static size_t GetCallFrameTopOffset(bool isArch32)
74     {
75         return GetOffset<static_cast<size_t>(Index::CALLFRAME_TOP_INDEX)>(isArch32);
76     }
77 
GetReturnAddressOffsetAsmStackContext78     static size_t GetReturnAddressOffset(bool isArch32)
79     {
80         return GetOffset<static_cast<size_t>(Index::RETURN_ADDRESS_INDEX)>(isArch32);
81     }
82 
GetCallerFpOffsetAsmStackContext83     static size_t GetCallerFpOffset(bool isArch32)
84     {
85         return GetOffset<static_cast<size_t>(Index::CALLERFRAME_POINTER_INDEX)>(isArch32);
86     }
87 
GetSizeAsmStackContext88     static constexpr size_t GetSize(bool isArch32)
89     {
90         return isArch32 ? AsmStackContext::SizeArch32 : AsmStackContext::SizeArch64;
91     }
92 
93     alignas(EAS) size_t inlineDepth_ {0};
94     alignas(EAS) uintptr_t callFrameTop_{0};
95     alignas(EAS) uintptr_t returnAddr_{0};
96     alignas(EAS) uintptr_t callerFp_{0};
97     // out put data
98 };
99 
100 class FrameWriter;
101 class Deoptimizier {
102 public:
103     using ARKDeopt = kungfu::ARKDeopt;
104     using CalleeReg = kungfu::CalleeReg;
105     using CalleeRegAndOffsetVec = kungfu::CalleeRegAndOffsetVec;
106     using CommonArgIdx = kungfu::CommonArgIdx;
107     using DeoptType = kungfu::DeoptType;
108     using DwarfRegType = kungfu::LLVMStackMapType::DwarfRegType;
109     using DwarfRegAndOffsetType = kungfu::LLVMStackMapType::DwarfRegAndOffsetType;
110     using IntType = kungfu::LLVMStackMapType::IntType;
111     using LargeInt = kungfu::LLVMStackMapType::LargeInt;
112     using LocationTy = kungfu::LocationTy;
113     using OffsetType = kungfu::LLVMStackMapType::OffsetType;
114     using VRegId = kungfu::LLVMStackMapType::VRegId;
115 
116     explicit Deoptimizier(JSThread *thread, size_t depth);
117 
118     void CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle, size_t shift);
119     template<class T>
120     void AssistCollectDeoptBundleVec(FrameIterator &it, T &frame);
121     void CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle);
122     JSTaggedType ConstructAsmInterpretFrame();
123     void UpdateAndDumpDeoptInfo(kungfu::DeoptType type);
124     static PUBLIC_API std::string DisplayItems(kungfu::DeoptType type);
125     static PUBLIC_API int32_t EncodeDeoptVregIndex(int32_t index, size_t depth, size_t shift);
126     static PUBLIC_API size_t ComputeShift(size_t depth);
127     static int32_t DecodeVregIndex(OffsetType id, size_t shift);
128     static size_t DecodeDeoptDepth(OffsetType id, size_t shift);
GetThread()129     JSThread *GetThread() const
130     {
131         return thread_;
132     }
133 
GetLLVMDeoptRelocateSymbol()134     static const char *GetLLVMDeoptRelocateSymbol()
135     {
136         return "__llvm_deoptimize";
137     }
138 
139 private:
GetFrameIndex(CommonArgIdx index)140     size_t GetFrameIndex(CommonArgIdx index)
141     {
142         return static_cast<size_t>(index) - static_cast<size_t>(CommonArgIdx::FUNC);
143     }
GetFrameArgv(size_t idx)144     JSTaggedValue GetFrameArgv(size_t idx)
145     {
146         ASSERT(frameArgvs_ != nullptr);
147         ASSERT(idx < frameArgc_);
148         return JSTaggedValue(frameArgvs_[idx]);
149     }
GetFrameArgv(CommonArgIdx index)150     JSTaggedValue GetFrameArgv(CommonArgIdx index)
151     {
152         return GetFrameArgv(GetFrameIndex(index));
153     }
GetActualFrameArgs(int32_t index)154     JSTaggedValue GetActualFrameArgs(int32_t index)
155     {
156         index += NUM_MANDATORY_JSFUNC_ARGS;
157         return GetFrameArgv(static_cast<size_t>(index));
158     }
159     bool CollectVirtualRegisters(JSTaggedValue callTarget, Method *method, FrameWriter *frameWriter, size_t curDepth);
HasDeoptValue(size_t curDepth,int32_t index)160     bool HasDeoptValue(size_t curDepth, int32_t index) const
161     {
162         ASSERT(curDepth <= inlineDepth_);
163         return deoptVregs_.find({curDepth, static_cast<OffsetType>(index)}) != deoptVregs_.end();
164     }
GetDeoptValue(size_t curDepth,int32_t index)165     JSTaggedValue GetDeoptValue(size_t curDepth, int32_t index) const
166     {
167         ASSERT(curDepth <= inlineDepth_);
168         if (!HasDeoptValue(curDepth, index)) {
169             return JSTaggedValue::Undefined();
170         }
171         return deoptVregs_.at({curDepth, static_cast<OffsetType>(index)}).GetTaggedValue();
172     }
173     Method* GetMethod(JSTaggedValue &target);
174     void RelocateCalleeSave();
175     void Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth);
176     size_t GetCallSize(size_t curDepth, const uint8_t *resumePc);
177     void ClearCompiledCodeStatusWhenDeopt(JSFunction *fun, Method *method);
178     void ResetJitHotness(JSFunction *jsFunc) const;
179     JSThread *thread_ {nullptr};
180     uintptr_t *calleeRegAddr_ {nullptr};
181     size_t numCalleeRegs_ {0};
182     AsmStackContext stackContext_;
183 
184     std::map<std::pair<size_t, OffsetType>, JSHandle<JSTaggedValue>> deoptVregs_;
185     struct Context context_ {0, 0, {}};
186     std::unordered_map<size_t, size_t> pc_;
187     std::unordered_map<size_t, size_t> jumpSize_;
188     size_t frameArgc_ {0};
189     JSTaggedType *frameArgvs_ {nullptr};
190     bool traceDeopt_{false};
191     size_t inlineDepth_ {0};
192 };
193 
194 }  // namespace panda::ecmascript
195 #endif // ECMASCRIPT_DEOPTIMIZER_DEOPTIMIZER_H